如何对构造函数不带参数的对象建立有效的模拟套件?

时间:2019-02-11 02:24:59

标签: java junit mocking mockito

我有几年前做过的纸牌游戏,现在我已经了解了如何使用Mockito进行嘲笑。到目前为止,我的卡片对象看起来像:

  public Card(){
    this.value = new CardValue(determineFace());  //assigns the output of a randomly chosen card to Card's this.value
                                                  //by plugging a call to determineFace() into a CardValue
    this.suit = determineSuit(); //this.suit is assigned a suit at random

  }

其中defineFace()是:

  public static String determineFace(){ //determines a face at random so that CardValue in this.value's init has a parameter
    String f = null;

    int rand = (int)(Math.random()*13);

    if (rand == 0){
      f = "2";
    }
    if (rand == 1){
      f = "3";
    }
    if (rand == 2){
      f = "4";
    }
    if(rand == 3){
      f = "5";
    }
    if(rand == 4){
      f = "6";
    }
    if(rand == 5){
      f = "7";
    }
    if(rand == 6){
      f = "8";
    }
    if(rand == 7){
      f = "9";
    }
    if(rand == 8){
      f = "10";
    }
    if (rand == 9){
      f = "J";
    }
    if (rand == 10){
      f = "Q";
    }
    if (rand == 11){
      f = "K";
    }
    if(rand == 12){
      f = "A";
    }
    return f;

  }

西装是

的一部分
public enum Suit{
    CLUBS, DIAMONDS, HEARTS, SPADES
  }

CardValue为:

  protected String face; //a CardValue's verbal name
  protected int numeric; //a CardValue's numeric value 

  public CardValue(String faceVal){
    face = faceVal; // set's a CV's face name passed into the constructor
    numeric = findNumericVal(faceVal); //sets the numeric value equal to the output of the call to findNumericVal on the faceVal
  }

但是,我对如何将CardValue模拟到Mockito感到很困惑,因此可以测试Card的方法。我也想测试CardValue的方法。我不太确定是否要使用@InjectMocks bc,似乎总是将其与没有args参数的对象一起使用。在尝试使用JUnit和Mockito进行模拟并对其进行测试时,我遇到了错误的情况,即在这些paren中使用错误的类型尝试了thenReturn()的情况下,我断言了在null中显示为null的值。如何对对象进行有效的模拟?

1 个答案:

答案 0 :(得分:0)

欢迎使用Stackoverflow!

这是一个没有模拟的解决方案,因为我看不到使用模拟的理由。

您需要做的就是在测试中用自定义函数替换随机函数。

AuthorityUrl类具有一个静态字段Card,它将在测试中被覆盖。顺便说一句,我将randomGenerator简化为一行,并删除了显式构造函数,只是为了获得更紧凑的代码。

determineFace()

这是测试类的示例:

class Card {
    static Supplier<Integer> randomGenerator = () -> (int) (Math.random() * 13);

    static String[] supportedFs =
            new String[]{"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};

    final CardValue value = new CardValue(determineFace());
    final Suite suit = determineSuit();

    static String determineFace() {
        return supportedFs[randomGenerator.get()];
    }

    static Suite determineSuit() {
        // TODO: to be finished according to your logic.
        return Suite.CLUBS;
    }
}

当然,您可以使用数据提供程序为每个可能的随机值组合测试用例。

上述解决方案的一个坏处是,将不会测试实际的随机生成。对于这种情况,您可以使用真实随机生成进行测试,但将实际值匹配为受支持值的一部分:

public class CardTest {
    @Test
    public void cardConstructionWhenRandomIsZero() {
        // Given custom random generator which returns always 0.
        Card.randomGenerator = () -> 0;

        // When
        Card actualCard = new Card();

        // Then
        Assert.assertEquals("2", actualCard.value.face);
        Assert.assertEquals(0, actualCard.value.numeric);
        Assert.assertEquals(Suite.CLUBS, actualCard.suit);
    }

    @Test
    public void cardConstructionWhenRandomIsOne() {
        // Given custom random generator which returns always 1.
        Card.randomGenerator = () -> 1;

        // When
        Card actualCard = new Card();

        // Then
        Assert.assertEquals("3", actualCard.value.face);
        Assert.assertEquals(0, actualCard.value.numeric);
        Assert.assertEquals(Suite.CLUBS, actualCard.suit);
    }
}

更新:基于评论。

如果您仍然想使用@Test public void cardConstructionWithRealRandom() { // When Card actualCard = new Card(); // Then Assert.assertThat(actualCard.value.face, Matchers.isIn(Card.supportedFs)); } ,可以通过以下方式模拟随机生成器的行为:

Mockito

更新2 :基于评论。

@Test
public void cardConstructionWhenRandomIsZero() {
    // Given custom random generator which returns always 0.
    Card.randomGenerator = Mockito.mock(Supplier.class);
    Mockito.when(Card.randomGenerator.get()).thenReturn(0);

    // When
    Card actualCard = new Card();

    // Then
    Assert.assertEquals("2", actualCard.value.face);
    Assert.assertEquals(0, actualCard.value.numeric);
    Assert.assertEquals(Suite.CLUBS, actualCard.suit);
}