2016-04-13 1 views
0

J'ai une méthode utilitaire utilisée dans des centaines de tests pour simuler la valeur de retour d'un randomiseur personnalisé. Voici un modèle (très artificielle) de mon code:Utiliser un `when` comme vérification

interface CardRandomiser{ 
    Card getCard(Suit suit); 
} 

void mockCard(Suit suit, Face face) { 
    CardRandomiser rand = mock(CardRandomiser.class); 
    when(rand.getCard(suit)).thenReturn(new Card(suit, face)); 
    Game.setCardRandomiser(rand); 
} 

Cela peut ensuite être utilisé comme:

mockCard(Suit.CLUBS, Face.QUEEN); 
Card card = pickACardAnyCard(); 
assertThat(card.getFace(), is(Face.QUEEN)); 

Cependant, cela fait quelques bugs un peu difficile à ramasser. Si la méthode sous test demande incorrectement Suit.HEARTS, le mock renvoie null et l'assertion échoue correctement. Mais il est impossible de dire à travers le message d'erreur ce qui a été passé au faux.

Clairement, je pouvais gérer cela avec un verify. Je pourrais passer le simulacre hors de la fonction mockCard et ensuite vérifier séparément qui a été appelé avec la valeur correcte. Mais cela encombre vraiment les affirmations des tests qui ne sont pas vraiment liées à ce qui est testé. Étant donné que cette méthode est appelée à chaque fois que je spécifie une valeur d'argument attendue, je préférerais mettre l'assertion à un endroit. Notez que cela se produit tous avant la méthode en cours de test est appelée.

Idéalement, j'aimerais que l'instruction when lève une exception si elle est appelée avec une valeur inattendue. Quelque chose comme:

when(rand.getCard(suit)).thenReturn(new Card(suit, face)); 
when(rand.getCard(intThat(not(is(suit))))).thenThrow(new IllegalArgumentException()); 

Cela fonctionne et arrête le test lorsque getCard est appelé ce qui est mieux. Mais cela ne me permet toujours pas de montrer quel était l'argument incorrect.

Je l'ai également essayé en utilisant un ArgumentCaptor puis en vérifiant la valeur capturée. Mais il est clair qu'ils sont pour les déclarations verify plutôt que when.

Existe-t-il une méthode Mockito standard, ou dois-je encombrer mes tests avec des instructions verify?

Répondre

2

Vous pouvez configurer la réponse mockito à l'aide de thenAnswer, par ex.

private CardRandomiser mockCard(final Suit suit, final Face face) { 
    CardRandomiser rand = mock(CardRandomiser.class); 

    when(rand.getCard(any(Suit.class))).thenAnswer(new Answer<Card>() { 
     @Override 
     public Card answer(InvocationOnMock invocation) throws Throwable { 
      if(!suit.equals(invocation.getArguments()[0])) { 
       throw new IllegalArgumentException(
         String.format("Value %s passed, but mocked for %s", invocation.getArguments()[0], suit)); 
      } 
      return new Card(suit, face); 
     } 
    }); 

    return rand; 
} 
+0

C'est parfait. Merci. – sprinter