如何测试使用Random()但不能选择相同数字两次的方法

时间:2016-11-25 08:20:39

标签: java testing random mockito

我正在创建一个小型Java游戏,该游戏从原始数据列表(使用Random().nextInt())类型中随机选择并询问哪个类型更大(或者它们是否相同)。我也做了这样的话,如果选择了相同的原始数据类型,那么再次调用random.nextInt()以确保选择不同。

我现在的麻烦在于测试代码的工作原理。下面是Game.class:

static final PrimitiveDataType BOOLEAN_TYPE = new PrimitiveDataType("boolean", 0);
    static final PrimitiveDataType BYTE_TYPE = new PrimitiveDataType("byte", 8);
    static final PrimitiveDataType SHORT_TYPE = new PrimitiveDataType("short", 16);
    static final PrimitiveDataType CHAR_TYPE = new PrimitiveDataType("char", 16);
    static final PrimitiveDataType INT_TYPE = new PrimitiveDataType("int", 32);
    static final PrimitiveDataType LONG_TYPE = new PrimitiveDataType("long", 64);
    static final PrimitiveDataType FLOAT_TYPE = new PrimitiveDataType("float", 32);
    static final PrimitiveDataType DOUBLE_TYPE = new PrimitiveDataType("double", 64);
static List<PrimitiveDataType> PRIMITIVE_TYPES = Arrays.asList(BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE,
        INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE);

static List<PrimitiveDataType> chosenDataTypes = new ArrayList<PrimitiveDataType>();

private static int numberOfQuestions; 

static Random numberGenerator = new Random();

static void setChosenDataTypeIndexs(Random numberGenerator) {




    int choice1 =  numberGenerator.nextInt(PRIMITIVE_TYPES.size()-1)+0;
    int choice2 =  numberGenerator.nextInt(PRIMITIVE_TYPES.size()-1)+0;

    System.out.println("Random Roll (1) " +choice1);
    System.out.println("Random Roll (2) " +choice2);
    do {

        choice2 = numberGenerator.nextInt(PRIMITIVE_TYPES.size()-1)+0;

    } while (choice1==choice2);

    Game.chosenDataTypes.add(PRIMITIVE_TYPES.get(choice1));
    Game.chosenDataTypes.add(PRIMITIVE_TYPES.get(choice2));

}

static PrimitiveDataType getChosenDataTypeIndexs(int i) {
    return chosenDataTypes.get(i);
}

public static void setNumberOfQuestions(int i) {

    numberOfQuestions = i;

}

我已经和Mockito一起编写了一个测试类,但是我不确定我是否因为骰子滚动输出相同的数字而通过测试而正确地嘲笑。另外,如果我将Random.nextInt()的输出模拟为特定的不会产生无限循环,因为它会查找不同的数字?

public class GameTest {





@Test
public void getChosenDataTypesTest(){


    Random randomNumberMock = Mockito .mock(Random.class);
    when(randomNumberMock.nextInt()).thenReturn(1);

    Game.setChosenDataTypeIndexs(randomNumberMock);

    assertNotEquals(Game.chosenDataTypes.get(0), Game.chosenDataTypes.get(1));

    verify(randomNumberMock,times(2)).nextInt();




}
@Test
public void setNumberOfQuestionsTest(){




    Game.setNumberOfQuestions(1);

    assertEquals(1,Game.getNumberOfQuestions());


}

编辑:经过多次搜索,我被建议在GameRunner中注入一个Picker接口,可以换出测试选择器,输出固定的选择。我还创建了一个Picks类来负责选择Primitive数据类型。这一点运作良好,完全消除了使用模拟框架的需要。

fixedPrimitivePicker使用了一堆PrimitiveDataTypes,每次都会弹出PrimitiveDataType个对象

package org.FaneFonseka.LearningGames2;

import org.junit.Before;
import org.junit.Test;

import java.util.Stack;


/**
 * Created by Fane on 23/12/2016.
 */
public class PicksTest {


private Picks picks;
private Picker fixedPrimitivePicker;
private Stack<PrimitiveDataType> primitiveDataTypeStack;
private PrimitiveDataType primitive1;
private PrimitiveDataType primitive2;
private PrimitiveDataType primitive3;

@Before
public void setup() {


    primitiveDataTypeStack = new Stack<PrimitiveDataType>();
    primitiveDataTypeStack.push(primitive3 = new PrimitiveDataType("int", 32));
    primitiveDataTypeStack.push(primitive2 = new PrimitiveDataType("boolean", 1));
    primitiveDataTypeStack.push(primitive1 = new PrimitiveDataType("boolean", 1));

    fixedPrimitivePicker = new Picker() {

        public PrimitiveDataType pick() {

            return primitiveDataTypeStack.pop();

        }
    };
    picks = new Picks(fixedPrimitivePicker);

}

@Test
public void setFirstPickTest() {

    picks.setPicks();

    assert picks.getFirstPick().equals(primitive1);


}

@Test
public void setSecondPickTest() {

    picks.setPicks();
    assert picks.getSecondPick().equals(primitive3);
}

@Test
public void secondPickIsDifferentFromFirstPickTest() {

    picks.setPicks();
    assert !picks.getFirstPick().equals(picks.getSecondPick());

}



}

和Picks Class:

package org.FaneFonseka.LearningGames2;

class Picks {
private PrimitiveDataType firstPick;
private PrimitiveDataType secondPick;
private Picker randomPrimitivePicker;

Picks(Picker randomPrimitivePicker) {
    this.randomPrimitivePicker = randomPrimitivePicker;
}

boolean firstPickGreaterThanSecondPick() {

    System.out.println(getFirstPick().getMemorySizeInBits() > getSecondPick().getMemorySizeInBits());
    return getFirstPick().getMemorySizeInBits() > getSecondPick().getMemorySizeInBits();
}

boolean secondPickGreaterThanFirstPick() {

    System.out.println(getFirstPick().getMemorySizeInBits() < getSecondPick().getMemorySizeInBits());
    return getFirstPick().getMemorySizeInBits() < getSecondPick().getMemorySizeInBits();
}

boolean firstPickIsSameSizeAsSecondPick() {
    System.out.println(getFirstPick().getMemorySizeInBits() == getSecondPick().getMemorySizeInBits());
    return getFirstPick().getMemorySizeInBits() == getSecondPick().getMemorySizeInBits();
}

void setPicks() {
    setFirstPick(randomPrimitivePicker);
    setSecondPick(randomPrimitivePicker);

}

private void setFirstPick(Picker randomPrimitivePicker) {

    this.firstPick = randomPrimitivePicker.pick();
}

PrimitiveDataType getFirstPick() {

    return this.firstPick;
}

private void setSecondPick(Picker randomPrimitivePicker) {

    PrimitiveDataType pick;

    do {
        pick = randomPrimitivePicker.pick();
    } while (pick.equals(firstPick));

    this.secondPick = pick;

}

PrimitiveDataType getSecondPick() {

    return secondPick;
}


}

如果你想看到项目的其余部分,可以在这里找到:

https://github.com/fane247/LearningGames2

1 个答案:

答案 0 :(得分:5)

您可以使用Chained stubbing为您的测试添加多样性,这样您就不会使用随机返回的相同数字进行测试。

 when(randomNumberMock.nextInt())
   .thenReturn(4)
   .thenReturn(12);

您还可以参数化您的测试。以下是TestNG的示例。

@DataProvider()
public static Object[][] randomNumbers() {
    return new Object[][] {{2, 3}, {6, 7}, {19, 15}};
}

@Test(dataProvider = "random")
public void getChosenDataTypesTest(int first, int second) {
 when(randomNumberMock.nextInt())
   .thenReturn(first)
   .thenReturn(second);
} 

JUnit具有parameterized tests的类似功能。

编辑: 模拟方法必须是

  

nextInt(anyInt())

因为你正在调用nextInt(int bound)而不是nextInt()。

when(randomNumberMock.nextInt(anyInt())
   .thenReturn(4)
   .thenReturn(12);