Как я могу сделать эффективный набор насмешек для объектов, которые конструкторы не принимают аргументов? - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть карточная игра, которую я сделал несколько лет назад, и теперь я узнал о насмешках с 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
  }

, где CardValuea:

  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, я получил ошибки о том, что thenReturn () был опробован с неверным типом в этих скобках, я получил значения, которые в моих утверждениях были показаны как нулевые.Как я могу сделать эффективные макеты моих объектов?

1 Ответ

0 голосов
/ 11 февраля 2019

Добро пожаловать на борт Stackoverflow!

Это решение без насмешек, потому что я не вижу причин использовать насмешки.

Все, что вам нужно, это заменить случайную функцию пользовательскойодин в тестах.

Класс 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, вы можете эмулировать поведение генератора случайных чисел следующим образом:

@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);
}

UPDATE 2 : на основекомментарии.

@Mock
Supplier<Integer> mockedRandomGenerator;

@Test
public void cardConstructionWhenRandomIsZero() {
    // Given custom random generator which returns always 0.
    Card.randomGenerator = mockedRandomGenerator;
    Mockito.when(mockedRandomGenerator.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);
}
...