Mockito ArgumentMatchers

1. Vue d'ensemble

Ce didacticiel montre comment utiliser ArgumentMatcher et en quoi il diffère de ArgumentCaptor .

Pour une introduction au framework Mockito, veuillez vous référer à cet article.

2. Dépendances de Maven

Nous devons ajouter un seul artefact:

 org.mockito mockito-core 2.21.0 test 

La dernière version de Mockito est disponible sur Maven Central .

3. ArgumentMatchers

Il est possible de configurer une méthode simulée de différentes manières. L'un d'eux consiste à renvoyer des valeurs fixes:

doReturn("Flower").when(flowerService).analyze("poppy");

Dans l'exemple ci-dessus, la chaîne «Flower» est renvoyée uniquement lorsque le service d'analyse reçoit la chaîne «poppy».

Mais peut-être devons-nous répondre à une gamme plus large de valeurs ou à des valeurs préalablement inconnues .

Dans tous ces scénarios, nous pouvons configurer nos méthodes simulées avec des matchers d' argument :

when(flowerService.analyze(anyString())).thenReturn("Flower");

Maintenant, à cause du matcher d'arguments anyString , le résultat sera le même quelle que soit la valeur que nous passons à analyser. ArgumentMatchers nous permet une vérification ou un stubbing flexible.

Dans le cas où une méthode a plus d'un argument, il n'est pas possible d'utiliser ArgumentMatchers pour seulement certains des arguments . Mockito vous oblige à fournir tous les arguments soit par correspondance, soit par valeurs exactes.

Un exemple suivant est une approche incorrecte à ceci:

abstract class FlowerService { public abstract boolean isABigFlower(String name, int petals); } FlowerService mock = mock(FlowerService.class); when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);

Pour résoudre ce problème et conserver le nom de chaîne "poppy" comme vous le souhaitez, nous utiliserons le matcher eq :

when(mock.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);

Il y a deux autres points à prendre en compte lorsque des matchers sont utilisés:

  • Nous ne pouvons pas les utiliser comme valeur de retour , une valeur exacte est requise lors du stubbing des appels
  • Enfin, nous ne pouvons pas utiliser arguments matchers en dehors de la vérification ou stubbing

Dans le dernier cas, Mockito détectera l'argument mal placé et lèvera une InvalidUseOfMatchersException .

Un mauvais exemple pourrait être:

String orMatcher = or(eq("poppy"), endsWith("y")); verify(mock).analyze(orMatcher);

La façon d'implémenter le code ci-dessus est:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

Mockito fournit également des AdditionalMatchers pour implémenter des opérations logiques communes ('not', 'et', 'ou') sur ArgumentMatchers qui correspondent à la fois aux types primitifs et non primitifs:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

4. Correspondance d'arguments personnalisés

Créer notre matcher peut être utile pour sélectionner la meilleure approche possible pour un scénario donné et produire un test de la plus haute qualité , propre et maintenable.

Par exemple, nous pourrions avoir un MessageController qui délivre des messages. Il recevra un MessageDTO , et à partir de là, il créera un message à remettre par MessageService .

Notre vérification sera simple, vérifiez que nous avons appelé le MessageService exactement 1 fois avec n'importe quel message:

verify(messageService, times(1)).deliverMessage(any(Message.class));

Parce que le message est construit à l' intérieur de la méthode à l'essai , nous sommes obligés d'utiliser tout comme matcher .

Cette approche ne nous permet pas de valider les données à l'intérieur du Message , qui peuvent être différentes des données à l'intérieur de MessageDTO .

Pour cette raison, nous allons implémenter un matcher d'arguments personnalisé:

public class MessageMatcher implements ArgumentMatcher { private Message left; // constructors @Override public boolean matches(Message right) { return left.getFrom().equals(right.getFrom()) && left.getTo().equals(right.getTo()) && left.getText().equals(right.getText()) && right.getDate() != null && right.getId() != null; } }

Pour utiliser notre matcher, nous devons modifier notre test et remplacer tout par argThat :

verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));

Nous savons maintenant que notre instance Message aura les mêmes données que notre MessageDTO .

5. Correspondance d'arguments personnalisés et ArgumentCaptor

Les deux techniques de correspondance d' arguments personnalisés et ArgumentCaptor peuvent être utilisées pour s'assurer que certains arguments ont été passés aux mocks.

Cependant, ArgumentCaptor peut être un meilleur ajustement si nous en avons besoin pour affirmer des valeurs d'argument pour terminer la vérification ou si notre correspondance d' arguments personnalisée n'est pas susceptible d'être réutilisée .

Les matchers d'arguments personnalisés via ArgumentMatcher sont généralement meilleurs pour le stubbing.

6. Conclusion

Dans cet article, nous avons exploré une fonctionnalité de Mockito , ArgumentMatcher et sa différence avec ArgumentCaptor .

Comme toujours, le code source complet des exemples est disponible à l'adresse over sur GitHub.