Comment utiliser ArgumentCaptor pour le stubbing?

161

Dans la documentation et les javadocs Mockito, il est dit

Il est recommandé d'utiliser ArgumentCaptor avec vérification mais pas avec stubbing.

mais je ne comprends pas comment ArgumentCaptor peut être utilisé pour le stubbing. Quelqu'un peut-il expliquer la déclaration ci-dessus et montrer comment ArgumentCaptor peut être utilisé pour le stubbing ou fournir un lien qui montre comment cela peut être fait?

Je ne peux pas dire
la source
1
Explication super courte et agréable ici: dzone.com/articles
Benj

Réponses:

271

En supposant la méthode suivante pour tester:

public boolean doSomething(SomeClass arg);

La documentation Mockito indique que vous ne devez pas utiliser captor de cette manière:

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
assertThat(argumentCaptor.getValue(), equalTo(expected));

Parce que vous pouvez simplement utiliser matcher pendant le stubbing:

when(someObject.doSomething(eq(expected))).thenReturn(true);

Mais la vérification est une autre histoire. Si votre test doit s'assurer que cette méthode a été appelée avec un argument spécifique, utilisez ArgumentCaptoret c'est le cas pour lequel elle est conçue:

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
assertThat(argumentCaptor.getValue(), equalTo(expected));
Rorick
la source
Merci d'avoir répondu. J'ai une question. Dans le troisième bloc de code, nous savons que true n'est retourné que lorsque attendu est passé à doSomething. Mais quand true est-il renvoyé dans le deuxième bloc de code? Ou est-ce que someObject retourne toujours true pour someMethod dans ce cas?
Je ne peux pas dire
Hm, je crois que vous vouliez dire "Mais quand est-ce que true est renvoyé dans le troisième bloc de code?". Dans le troisième bloc de code, nous ne nous soucions tout simplement pas de la valeur de retour et laissons celle par défaut. Pour booléen, ce n'est falsepas le cas true.
Rorick le
Non, j'ai compté tous les blocs de fond gris comme des blocs de code. Y compris la première doublure. Je faisais référence à la ligne when (someObject.doSomething (argumentCaptor.capture ())). ThenReturn (true);
Je ne peux pas dire
Ah désolé. Oui, dans ce cas, true sera toujours retourné.
Rorick
3
pas sûr que la raison de "ne pas utiliser avec le stubbing" est une raison simple. les matchers ne nous donnent pas l'argument attendu réel (juste le type) et conduisent à être d'accord avec les tests réussis malgré des arguments qui pourraient être erronés.
dtc
0

La ligne

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);

ferait la même chose que

when(someObject.doSomething(Matchers.any())).thenReturn(true);

Ainsi, utiliser argumentCaptor.capture () lors du stubbing n'a aucune valeur ajoutée. Utiliser Matchers.any () montre mieux ce qui se passe réellement et est donc meilleur pour la lisibilité. Avec argumentCaptor.capture (), vous ne pouvez pas lire quels arguments correspondent vraiment. Et au lieu d'utiliser any (), vous pouvez utiliser des matchers plus spécifiques lorsque vous avez plus d'informations (classe de l'argument attendu), pour améliorer votre test.

Et un autre problème: si vous utilisez argumentCaptor.capture () lors du stubbing, il n'est pas clair combien de valeurs vous devriez vous attendre à capturer après vérification. Nous voulons capturer une valeur pendant la vérification, pas pendant le stubbing car à ce stade, il n'y a pas encore de valeur à capturer. Alors, qu'est-ce que les capteurs d'arguments capturent la méthode de capture pendant le stubbing? ou ne capte-t-il rien? Je n'ai pas la réponse à cette question. Je considère que c'est un comportement indéfini et je ne veux pas utiliser un comportement indéfini.

Stefan Mondelaers
la source
0

Hypothétiquement, si la recherche vous a amené sur cette question, vous voulez probablement ceci:

doReturn(someReturn).when(someObject).doSomething(argThat(argument -> argument.getName().equals("Bob")));

Pourquoi? Parce que comme moi, vous valorisez le temps et vous n'allez pas mettre en œuvre .equalsuniquement pour le seul scénario de test.

Et 99% des tests échouent avec null retourné de Mock et dans une conception raisonnable, vous éviteriez nullà tout prix le retour , l'utilisation Optionalou le déplacement vers Kotlin. Cela implique que cela verifyn'a pas besoin d'être utilisé souvent et que les ArgumentCaptors sont tout simplement trop fastidieux à écrire.

Aubergine
la source