web-dev-qa-db-fra.com

Former des "grammaires" Mockito

Mockito semble être un cadre de stubbing/mocking assez doux pour Java. Le seul problème est que je ne trouve aucune documentation concrète sur les meilleures façons d'utiliser leur API. Les méthodes couramment utilisées dans les tests comprennent:

doXXX(???) : Stubber
when(T) : OngoingStubbing
then(T) : OngoingStubbing
verify(???) : T
given(T) : BDDOngoingStubbing
willXXX(???) : BDDStubber

Lorsque vous voyez des exemples de Mockito dans la pratique, vous voyez du code comme:

when(yourMethod()).thenReturn(5);

De tous les documents que j'ai lus, j'ai identifié plusieurs "modèles" de "grammaires" Mockito obtenus en chaînant ces appels de méthode comme dans l'exemple ci-dessus. Voici quelques modèles courants que j'ai trouvés:

Quand/Alors: quand (yourMethod ()). ThenReturn (5);

Given/Will: given (yourMethod ()). WillThrow (OutOfMemoryException.class);

Do/When: doReturn (7) .when (yourMock.fizzBuzz ());

Will/Given/Do: willReturn (any ()). Given (yourMethod ()). DoNothing ();

Verify/Do: verify (yourMethod ()). DoThrow (SomeException.class);

Ce qui m'étouffe, c'est comment sélectionner le bon modèle/combinaison d'appels de méthode pour modéliser mes cas de test. Il semble que vous puissiez les connecter en série dans des combos apparemment sans fin et je ne sais pas quel modèle convient à quel problème.

Certains Mockito Guru peuvent-ils aider à faire la lumière sur les modèles/combinaisons de méthodes Mockito utilisés pour quels types de cas de test (et pourquoi)? Merci d'avance!

42
IAmYourFaja

Mockito a souvent plusieurs façons de faire les choses.

Je me retrouve surtout à utiliser:

// Setup expectations
when(object.method()).thenReturn(value);
when(object.method()).thenThrow(exception);
doThrow(exception).when(object.voidMethod());


// verify things
verify(object, times(2)).method();
verify(object, times(1)).voidMethod();

J'ai constaté que je peux faire 95% de ce dont j'ai besoin avec ces trois types d'appels.

De plus, quelle version de Mockito utilisez-vous? Les constructions "given" et "will" ne sont pas présentes dans la dernière version (1.9.0+)

Cependant, il y a des cas où je veux que la valeur de retour ou l'exception réponde à l'entrée. Dans ce cas, vous pouvez utiliser l'interface Answer pour inspecter les arguments de la méthode et renvoyer une valeur appropriée.

public class ReturnFirstArg<T> implements Answer<T> {
    public T answer(InvocationOnMock invocation) {
        return invocation.getArguments()[0];
    }
}

when(object.method(7)).thenAnswer(new ReturnFirstArg<Integer>());
16
Matt

Il y a plusieurs inconvénients au when/thenReturn, when/thenThrow et when/then syntaxes. Par exemple,

  • Dans le cas de when/thenReturn, si le type de retour est un générique avec un caractère générique et que vous souhaitez renvoyer une maquette du même type, vous ne pourrez pas éviter un avertissement de compilation.
  • Vous ne pouvez pas utiliser when/thenThrow et when/then pour une méthode void.
  • Vous ne pouvez pas utiliser ces syntaxes sur les espions Mockito.
  • Vous ne pouvez appeler when qu'une seule fois pour chaque combinaison de faux objet, méthode et arguments, sauf si vous appelez reset sur le faux.
  • L'appel de when plusieurs fois pour une combinaison d'objet simulé et de méthode, lorsque vous utilisez des comparateurs d'arguments, peut entraîner des problèmes.

Je trouve ces cas difficiles à retenir. Donc, au lieu d'essayer de garder une trace du moment où le when/thenReturn, when/thenThrow et when/then les syntaxes fonctionneront et ne fonctionneront pas, je préfère les éviter complètement, en faveur de doReturn/when, doThrow/when et doAnswer/when alternatives. C'est-à-dire que vous aurez parfois besoin de doReturn/when, doThrow/when et doAnswer/when, et vous pouvez TOUJOURS utiliser ces méthodes, il est inutile d'apprendre à utiliser when/thenReturn, when/thenThrow et when/then.

Notez que doReturn, doThrow et doAnswer peuvent être chaînés ensemble de la même manière que thenReturn, thenThrow et then. Ce qu'ils n'ont pas, c'est une option pour retourner plusieurs valeurs (ou lever plusieurs exceptions, ou exécuter plusieurs réponses) dans un seul appel à doReturn, doThrow et doAnswer. Mais je trouve que je dois faire cela si rarement, que cela n'a pas vraiment d'importance.

Il y a un autre inconvénient à doReturn, que je considère comme insignifiant. Vous n'obtenez pas de temps de compilation pour vérifier le type de son argument, comme vous le faites avec when/thenReturn. Donc, si vous obtenez un type d'argument incorrect, vous ne le découvrirez pas avant d'exécuter votre test. Franchement, je m'en fiche.

En résumé, j'utilise Mockito depuis plus de deux ans et je considère que l'utilisation cohérente de doReturn, doThrow et doAnswer est une meilleure pratique Mockito. D'autres utilisateurs de Mockito ne sont pas d'accord.

34
Dawood ibn Kareem

Les choses semblent en fait beaucoup plus simples que vous ne le pensiez

REF: http://static.javadoc.io/org.mockito/mockito-core/2.7.12/org/mockito/Mockito.html

Vérifiez :

Pour utiliser Mockito, vous devez comprendre une philosophie de base de Mockito: le stubbing et la vérification sont séparés. Par conséquent, le "vérifier/faire" que vous avez mentionné fait en fait le travail de "vérification", tandis que les 4 autres "grammaires" sont destinées au stubbing. Le stubbing définit la façon dont l'objet simulé réagira dans différentes situations. La vérification consiste à s'assurer que les simulations sont invoquées comme prévu, lors de l'appel précédent au système testé (SUT).

Quand/Alors, Étant donné/Volonté :

Ensuite, il s'agit des familles "Quand" et "Étant donné". Vous pouvez simplement les traiter comme des alias les uns des autres. La famille "Given" est ajoutée dans Mockito 1.8.x pour la rendre plus alignée sur les pratiques BDD.

DoXxx :

Dans le cas normal, nous utilisons principalement when(xxx).then(...) (et given(...).will(...)). Cependant, il y a des cas où la syntaxe ne fonctionne pas. Le cas le plus évident est lorsque le type de retour de la méthode tronquée est nul. Dans ce cas, when(mockObj.voidMethod()).thenThrow(anException) ne va pas compiler. Comme solution de contournement, une syntaxe alternative de Do/When est créée, de sorte que vous pouvez écrire la ligne précédente sous la forme doThrow(anException).when(mockObj.voidMethod())

9
Adrian Shum