Mockito - différence entre doReturn () et when ()

196

Je suis actuellement en train d'utiliser Mockito pour simuler mes objets de couche de service dans une application Spring MVC dans laquelle je veux tester mes méthodes de contrôleur. Cependant, comme je l'ai lu sur les spécificités de Mockito, j'ai trouvé que les méthodes étaient doReturn(...).when(...)équivalentes à when(...).thenReturn(...). Donc, ma question est quel est l'intérêt d'avoir deux méthodes qui font la même chose ou quelle est la différence subtile entre doReturn(...).when(...)et when(...).thenReturn(...)?

Toute aide serait appréciée.

panthère noire
la source
1
Le javadoc a quelques cas où il doReturn()est utile.
Sotirios Delimanolis
5
Je pense que l'une des principales différences est que doReturn (...). Lorsque (..) est plus ancien et que ce type n'est pas sûr et que nous pouvons donc l'utiliser parfois lorsque le compilateur continue de se plaindre du casting. Le quand (..). Puis le retour (..) est bien meilleur en termes de sécurité de type
user2511882

Réponses:

227

Les deux syntaxes pour le stubbing sont à peu près équivalentes. Cependant, vous pouvez toujours utiliser doReturn/whenpour le tronçonnage; mais il y a des cas où vous ne pouvez pas utiliser when/thenReturn. Les méthodes de stubbing void en font partie. D'autres incluent l'utilisation avec des espions Mockito et le tronçonnage de la même méthode plus d'une fois.

Une chose qui when/thenReturnvous donne, ce doReturn/whenn'est pas le cas, est la vérification de type de la valeur que vous retournez, au moment de la compilation. Cependant, je crois que cela n'a presque aucune valeur - si vous avez un mauvais type, vous le saurez dès que vous exécuterez votre test.

Je recommande fortement d'utiliser uniquement doReturn/when. Il ne sert à rien d'apprendre deux syntaxes quand on le fera.

Vous voudrez peut-être vous référer à ma réponse à Forming Mockito "grammars" - une réponse plus détaillée à une question très proche.

Dawood ibn Kareem
la source
16
Je suis un peu en désaccord avec David. Je rencontre souvent des situations où je renvoie le mauvais type lors de l'utilisation doReturn/whenet passe les prochaines minutes à comprendre ce qui ne va pas. La vérification du type de type de compilation devient extrêmement utile avec when/thenReturn.
Saket
11
Gardez à l'esprit que Mockito vous recommande d'utiliser use when/thenReturnau lieu de doReturn/when.
CodyEngel
2
@CodyEngel et il n'y a aucune raison pour une telle recommandation, autre que ce que j'ai décrit dans mes réponses ici et sur stackoverflow.com/q/11462697 . Il y a plusieurs années, j'en ai discuté avec Brice Dutheil, qui est actuellement le développeur principal par intérim de Mockito, et au meilleur de ma mémoire, il est d'accord. Je vais lui demander de poster un commentaire ici (aucune garantie qu'il le fera).
Dawood ibn Kareem
18
Le javadoc déclare que doReturn/whenc'est un compromis. L'équipe ne recommande pas d'une manière ou d'une autre mais notez que l' when/thenapproche est plus intuitive, plus lisible et offre une vérification du temps de compilation, c'est l'approche qui a rendu Mockito populaire et facile à utiliser, n'oubliez pas que lorsque la base de code est partagée par compétences diverses dans votre équipe; pourtant, il présente des inconvénients concernant les espions et les méthodes de nullité.
Brice
5
Juste pour mémoire: doReturn()a le gros inconvénient de se transformer en codage de style YODA des appels de méthode. La chose est ensuite écrite en premier. La plupart des gens lisent de gauche à droite; vous devez donc vous rappeler constamment d'inverser la logique de retour dans votre tête.
GhostCat
199

Les deux approches se comportent différemment si vous utilisez un objet espion (annoté avec @Spy) au lieu d'une maquette (annoté avec @Mock):

  • when(...) thenReturn(...) effectue un véritable appel de méthode juste avant que la valeur spécifiée ne soit renvoyée. Donc, si la méthode appelée lève une exception, vous devez y faire face / la mocker etc. Bien sûr, vous obtenez toujours votre résultat (ce que vous définissez dans thenReturn(...))

  • doReturn(...) when(...) n'appelle pas du tout la méthode .

Exemple:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

Tester:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");
akcasoy
la source
37
Ce comportement ne fonctionne que pour les objets espionnés, car ils sont "wrapper" d'objets réels. Dans le cas d'objets moqués, peu importe que ce soit quand / alorsRetour ou doRetour / quand. Les objets simulés n'appellent jamais de vraies méthodes.
Rafael Orágio
Pourriez-vous s'il vous plaît donner plus d'informations pourquoi avons-nous besoin d'utiliser cette fonctionnalité? Je ne vois pas de cas d'utilisation pratique. Le but du test est de confirmer l'exactitude du code dans différents cas d'utilisation. Si le calll de la méthode lève le test d'exception doit lever l'exception, ne renvoie pas de valeur
Gleichmut
@Gleichmut C'était un scénario hypothétique, où je montre l'utilisation / l'avantage de doReturn. Dans une application réelle, une méthode qui retourne juste une exception n'a bien sûr aucun sens .. mais vous avez des méthodes (probablement pas aussi fines que celle-ci) qui peuvent
lever des
1
Juste pour clarification: La méthode when (). ThenReturn () - appelle la méthode réelle (d'un espion - n'a pas d'importance pour les simulations) une seule fois. Cela se produit dans la ligne où vous spécifiez le comportement factice (lorsque ( myClass.anotherMethodInClass () .thenRet ...). Après cela, la méthode réelle n'est plus jamais appelée. Peut-être bon de savoir si vous vous attendiez à une logique de décorateur lors de la lecture de l'explication ci - dessus.
Jonas
Cela ne semble pas être un avantage doReturn(), cela ressemble à un abus de la bibliothèque. L'intérêt d'espionner au lieu de se moquer purement est de profiter de vrais appels. Ils mettent également en garde contre l'utilisation d'espions comme ceci: github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) (et recommandent d'étendre la classe et de remplacer la méthode à la place)
Matthew Read
13

Le javadoc Mockito semble dire pourquoi utiliser doReturn()au lieu d' when() utiliser Utiliser doReturn () dans les rares occasions où vous ne pouvez pas utiliser Mockito.when (Object).

Attention, Mockito.when (Object) est toujours recommandé pour le stubbing car il est sûr pour les arguments et plus lisible (en particulier lors du stubbing d'appels consécutifs).

Voici ces rares occasions où doReturn () est utile:

1. Quand espionner de vrais objets et appeler de vraies méthodes sur un espion apporte des effets secondaires

List list = new LinkedList(); List spy = spy(list);

// Impossible: la vraie méthode est appelée alors spy.get (0) lève IndexOutOfBoundsException (la liste est encore vide)

when(spy.get(0)).thenReturn("foo");

// Vous devez utiliser doReturn () pour le stubbing: doReturn("foo").when(spy).get(0);

2. Remplacer un stubbing d'exception précédent:

when(mock.foo()).thenThrow(new RuntimeException());

// Impossible: la méthode foo () tronquée d'exception est appelée, de sorte que RuntimeException est levée. when(mock.foo()).thenReturn("bar");

// Vous devez utiliser doReturn () pour le stubbing:

doReturn("bar").when(mock).foo(); Les scénarios ci-dessus montrent un compromis entre l'élégante syntaxe de Mockito. Notez cependant que les scénarios sont très rares. L'espionnage doit être sporadique et le tronçonnage d'exception est très rare. Sans oublier qu'en général, le remplacement du stubbing est une odeur de code potentielle qui indique trop de stubbing.


la source
6

Poursuivant cette réponse , il y a une autre différence que si vous voulez que votre méthode retourne des valeurs différentes par exemple quand elle est appelée pour la première fois, pour la deuxième fois, etc., vous pouvez passer des valeurs donc par exemple ...

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

Ainsi, elle renverra false lorsque la méthode est appelée dans le même scénario de test, puis elle renverra à nouveau et enfin true.

AZ_
la source