回答:
ランダムのラッパーを作成する必要があることに完全に同意するDavidの答えを拡張します。似たような質問で以前にそれについてほとんど同じ答えを書いたので、ここにそれの「クリフのノートバージョン」があります。
あなたがすべきことは、最初にラッパーをインターフェース(または抽象クラス)として作成することです:
public interface IRandomWrapper {
int getInt();
}
そして、これの具体的なクラスは次のようになります。
public RandomWrapper implements IRandomWrapper {
private Random random;
public RandomWrapper() {
random = new Random();
}
public int getInt() {
return random.nextInt(10);
}
}
あなたのクラスは次のとおりだとしましょう:
class MyClass {
public void doSomething() {
int i=new Random().nextInt(10)
switch(i)
{
//11 case statements
}
}
}
IRandomWrapperを正しく使用するには、クラスを変更して(コンストラクターまたはセッターを介して)メンバーとして取得する必要があります。
public class MyClass {
private IRandomWrapper random = new RandomWrapper(); // default implementation
public setRandomWrapper(IRandomWrapper random) {
this.random = random;
}
public void doSomething() {
int i = random.getInt();
switch(i)
{
//11 case statements
}
}
}
ラッパーをモックすることで、ラッパーを使用してクラスの動作をテストできるようになりました。モックフレームワークを使用してこれを行うことができますが、これも自分で簡単に行うことができます。
public class MockedRandomWrapper implements IRandomWrapper {
private int theInt;
public MockedRandomWrapper(int theInt) {
this.theInt = theInt;
}
public int getInt() {
return theInt;
}
}
クラスは次のように見えることを期待しているので、IRandomWrapper
テストで動作を強制するためにモックされたものを使用できるようになりました。JUnitテストの例を次に示します。
@Test
public void testFirstSwitchStatement() {
MyClass mc = new MyClass();
IRandomWrapper random = new MockedRandomWrapper(0);
mc.setRandomWrapper(random);
mc.doSomething();
// verify the behaviour for when random spits out zero
}
@Test
public void testFirstSwitchStatement() {
MyClass mc = new MyClass();
IRandomWrapper random = new MockedRandomWrapper(1);
mc.setRandomWrapper(random);
mc.doSomething();
// verify the behaviour for when random spits out one
}
お役に立てれば。
指定された範囲(0〜10)と指定された粒度(整数)があります。そのため、テストするときは、乱数を使用してテストしないでください。各ケースを順番にヒットするループ内でテストします。乱数をcaseステートメントを含むサブ関数に渡すことをお勧めします。これにより、サブ関数をテストすることができます。
PowerMockライブラリを使用してRandomクラスをモックし、そのnextInt()メソッドをスタブして期待値を返すことができます。必要ない場合は、元のコードを変更する必要はありません。
私はPowerMockitoを使用していますが、あなたの方法に似た方法をテストしました。JUnitテストを投稿したコードについては、次のようになります。
@RunWith(PowerMockRunner.class)
@PrepareForTest( { Random.class, ClassUsingRandom.class } ) // Don't forget to prepare the Random class! :)
public void ClassUsingRandomTest() {
ClassUsingRandom cur;
Random mockedRandom;
@Before
public void setUp() throws Exception {
mockedRandom = PowerMockito.mock(Random.class);
// Replaces the construction of the Random instance in your code with the mock.
PowerMockito.whenNew(Random.class).withNoArguments().thenReturn(mockedRandom);
cur = new ClassUsingRandom();
}
@Test
public void testSwitchAtZero() {
PowerMockito.doReturn(0).when(mockedRandom).nextInt(10);
cur.doSomething();
// Verify behaviour at case 0
}
@Test
public void testSwitchAtOne() {
PowerMockito.doReturn(1).when(mockedRandom).nextInt(10);
cur.doSomething();
// Verify behaviour at case 1
}
(...)
スイッチでさらにケースを追加する場合は、nextInt(int)呼び出しをスタブして任意のパラメーターを受信することもできます。
PowerMockito.doReturn(0).when(mockedRandom).nextInt(Mockito.anyInt());
きれいですね。:)
QuickCheckを使用してください!私は最近これで遊んで始めたばかりで、すごいです。ほとんどのクールなアイデアと同様に、Haskellから来ていますが、基本的なアイデアは、事前に用意されたテストケースをテストする代わりに、乱数ジェネレーターで作成できるようにすることです。そうすれば、おそらくxUnitで思いつく4〜6のケースの代わりに、コンピューターに数百または数千の入力を試行させ、どの入力が設定したルールに適合しないかを確認させることができます。
また、QuickCheckは、失敗したケースを見つけると、それを単純化して、失敗する可能性のある最も単純なケースを見つけられるようにします。(そしてもちろん、失敗したケースを見つけたら、それをxUnitテストに組み込むこともできます)
Javaには少なくとも2つのバージョンがあるように見えるため、その部分は問題になりません。