169 votes

Simuler que le premier appel échoue, le second réussit

Je veux 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 vérifier que s'il échoue une fois (ou deux) puis réussit, tout va bien ?

315voto

Jon Skeet Points 692016

De les docs :

Parfois, nous avons besoin de faire un stub avec différentes valeurs de retour/exceptions pour le même appel de méthode. Un cas d'utilisation typique pourrait être le mocking des itérateurs. La version originale de Mockito n'avait pas cette fonctionnalité pour promouvoir le mocking 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, il peut être utile de bloquer des appels consécutifs :

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");

46voto

David Wallace Points 23911

La façon la plus courte d'écrire ce que vous voulez est

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

Lorsque vous fournissez de multiples arguments à thenReturn comme ceci, chaque argument sera utilisé au maximum une fois, à l'exception du tout dernier argument, qui est utilisé autant de fois que nécessaire. Par exemple, dans ce cas, si vous faites l'appel 4 fois, vous obtiendrez "Success", "you failed", "you failed", "you failed".

40voto

anoneironaut Points 765

Comme le commentaire qui s'y rapporte est difficile à lire, je vais ajouter une réponse formatée.

Si vous essayez de faire cela avec un void qui ne fait que lever une exception, suivie d'une étape de non comportement, alors vous feriez quelque chose comme ceci :

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

8voto

Mohammed Elrashidy Points 1772

J'ai une situation différente, je voulais me moquer d'une void 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());

6voto

typoerrpr Points 880

Pour compléter ce y ce vous pouvez également utiliser une boucle pour enchaîner les appels simulés. Ceci est utile si vous avez besoin de simuler la même chose plusieurs fois, ou de simuler un certain modèle.

Eg (bien que farfelue) :

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());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X