Mockito ArgumentMatchers

Mockito ArgumentMatchers

1. Vue d'ensemble

Ce didacticiel montrehow to use the ArgumentMatcher and how it differs from the ArgumentCaptor.

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

2. Dépendances Maven

Nous devons ajouter un seul artefact:


    org.mockito
    mockito-core
    2.21.0
    test

La dernière version deMockito peut être trouvée surMaven Central.

3. ArgumentMatchers

Il est possible de configurer une méthode fictive 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 «fleur» deString est renvoyée uniquement lorsque le service d'analyse reçoit le «pavot» deString.

Maismaybe we need to respond to a wider range of values or beforehand unknown values.

Dans tous ces scénarios,we can configure our mocked methods with argument*matchers*:

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

Maintenant, à cause du matcher d'argumentanyString, 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.

Si une méthode a plus d'un argument,it isn’t possible to use ArgumentMatchers for only some of the arguments. Mockito vous oblige à fournir tous les arguments soit parmatchers, soit par des valeurs exactes.

Un exemple suivant est une approche incorrecte de 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 deString "poppy" comme vous le souhaitez, nous utiliseronseq matcher:

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

Il y a deux autres points à prendre en compte lorsquematchers  est utilisé:

  • We can’t use them as a return value, une valeur exacte est requise lors du stubbing des appels

  • Enfin,we can’t use argument matchers outside of verification or stubbing

Dans le dernier cas,Mockito détectera l'argument mal placé et lancera unInvalidUseOfMatchersException.

Un mauvais exemple pourrait être:

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

La manière d'implémenter le code ci-dessus est:

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

Mockito fournit égalementAdditionalMatchers pour implémenter des opérations logiques communes («non», «et», «ou») sur lesArgumentMatchers qui correspondent à la fois aux types primitifs et non primitifs:

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

4. Argumentaire personnalisé

Création deour matcher can be good to select the best possible approach for a given scenario and produce highest quality test, qui est propre et maintenable.

Par exemple, nous pourrions avoir unMessageController qui délivre des messages. Il recevra unMessageDTO, et à partir de cela, il créera unMessage à livrer parMessageService.

Notre vérification sera simple, vérifiez que nous avons appelé lesMessageService exactement 1 fois avecany Message:

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

Parce quethe Message is constructed inside the method under test, nous sommes obligés d'utiliserany commematcher.

Cette approche ne nous permet pas de valider les données à l'intérieur desMessage,which can be different compared to the data inside MessageDTO.

Pour cette raison, nous allons mettre en œuvre un correcteur 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;
    }
}

To use our matcher, we need to modify our test and replace any by argThat:

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

Nous savons maintenant que notre instanceMessage aura les mêmes données que nosMessageDTO.

5. Argumentaire personnalisé contre. ArgumentCaptor

Les deux techniquescustom argument matchers etArgumentCaptor peuvent être utilisées pour s'assurer que certains arguments ont été passés aux mocks.

Cependant,ArgumentCaptor may be a better fit if we need it to assert on argument values pour terminer la vérificationor our custom argument matcher is not likely to be reused.

LesCustom argument matchers viaArgumentMatcher sont généralement meilleurs pour le stubbing.

6. Conclusion

Dans cet article, nous avons exploré une fonctionnalité deMockito, ArgumentMatcher et sa différence avecArgumentCaptor.

Comme toujours, le code source complet des exemples est disponibleover on GitHub.