Simuler l'échec du premier appel, le deuxième appel réussit


119

Je souhaite utiliser Mockito pour tester le code (simplifié) ci-dessous. Je ne sais pas comment dire à Mockito d'échouer la première fois, puis de réussir la deuxième fois.

for(int i = 1; i < 3; i++) {
  String ret = myMock.doTheCall();

  if("Success".equals(ret)) {
    log.write("success");
  } else if ( i < 3 ) {
    log.write("failed, but I'll try again. attempt: " + i);
  } else {
    throw new FailedThreeTimesException();
  }
}

Je peux configurer le test de réussite avec:

Mockito.when(myMock).doTheCall().thenReturn("Success");

Et le test d'échec avec:

Mockito.when(myMock).doTheCall().thenReturn("you failed");

Mais comment puis-je tester que si cela échoue une (ou deux fois) puis réussit, tout va bien?

Réponses:


251

À partir de la documentation :

Parfois, nous devons stub avec une valeur de retour / une exception différente pour le même appel de méthode. Un cas d'utilisation typique pourrait être des itérateurs moqueurs. La version originale de Mockito n'avait pas cette fonctionnalité pour promouvoir la moquerie simple. Par exemple, au lieu d'itérateurs, on pourrait utiliser Iterable ou simplement des collections. Ceux-ci offrent des moyens naturels de stubbing (par exemple en utilisant de vraies collections). Dans de rares scénarios, le stubbing des appels consécutifs peut être utile, cependant:

when(mock.someMethod("some arg"))
   .thenThrow(new RuntimeException())
  .thenReturn("foo");

//First call: throws runtime exception:
mock.someMethod("some arg");

//Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));

Donc, dans votre cas, vous voudriez:

when(myMock.doTheCall())
   .thenReturn("You failed")
   .thenReturn("Success");

25
Cela m'a orienté dans la bonne direction (merci) pour mon scénario qui traitait des méthodes vides - dans ce cas, vous devez utiliser le style alternatif ...doThrow(new RuntimeException()).doNothing().when(myMock).doTheCall();
haggisandchips

38

Le moyen le plus court d'écrire ce que vous voulez est

when(myMock.doTheCall()).thenReturn("Success", "you failed");

Lorsque vous fournissez plusieurs arguments thenReturncomme ceci, chaque argument sera utilisé au plus une fois, à l'exception du tout dernier argument, qui est utilisé autant de fois que nécessaire. Par exemple, dans ce cas, si vous passez l'appel 4 fois, vous obtiendrez "Succès", "vous avez échoué", "vous avez échoué", "vous avez échoué".


22

Étant donné que le commentaire qui s'y rapporte est difficile à lire, j'ajouterai une réponse formatée.

Si vous essayez de le faire avec une voidfonction qui lève simplement une exception, suivie d'une étape de non-comportement, vous feriez quelque chose comme ceci:

Mockito.doThrow(new Exception("MESSAGE"))
            .doNothing()
            .when(mockService).method(eq());

4

Pour ajouter à ceci et à cette réponse, vous pouvez également utiliser une boucle pour enchaîner les appels simulés. Ceci est utile si vous devez vous moquer de la même chose plusieurs fois ou vous moquer d'un modèle.

Par exemple (même si c'est tiré par les cheveux):

import org.mockito.stubbing.Stubber;

Stubber stubber = doThrow(new Exception("Exception!"));
for (int i=0; i<10; i++) {
    if (i%2 == 0) {
        stubber.doNothing();
    } else {
        stubber.doThrow(new Exception("Exception"));
    }
}
stubber.when(myMockObject).someMethod(anyString());

En fait, je ne connaissais pas ce Stubber et je l'ai trouvé utile, +1.
Mihai Morcov

Cela devrait être la bonne réponse si vous avez besoin de la méthode call a void.
db80

4

J'ai une situation différente, je voulais simuler une voidfonction pour le premier appel et l'exécuter normalement au deuxième appel.

Cela fonctionne pour moi:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.