web-dev-qa-db-fra.com

Simuler le premier appel échoue, le deuxième appel réussit

Je veux utiliser Mockito pour tester le code (simplifié) ci-dessous. Je ne sais pas comment dire à Mockito de ne pas réussir 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 si cela échoue une fois (ou deux fois), alors tout va bien?

86
jb.

De les docs :

Parfois, nous devons stub avec une valeur de retour/une exception différente pour le même appel de méthode. Le cas d'utilisation typique pourrait être de se moquer des itérateurs. La version originale de Mockito ne disposait pas de cette fonctionnalité pour promouvoir les moqueries simples. Par exemple, au lieu d'itérateurs, vous pouvez utiliser Iterable ou simplement des collections. Celles-ci offrent des méthodes naturelles de substitution (par exemple, en utilisant de véritables collections). Dans de rares cas, il pourrait être utile de remplacer des appels consécutifs par 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");
200
Jon Skeet

Le moyen le plus rapide d’écrire ce que vous voulez est

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

Lorsque vous fournissez plusieurs arguments à thenReturn de cette manière, 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 effectuez l'appel 4 fois, vous obtiendrez "Succès", "Votre échec", "Votre échec", "Votre échec".

29
Dawood ibn Kareem

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 une fonction void qui lève juste une exception, suivie d'une étape sans comportement, alors vous feriez quelque chose comme ceci:

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

Pour ajouter à this et this répondre, vous pouvez également utiliser une boucle pour chaîner les appels simulés. Ceci est utile si vous avez besoin de vous moquer de la même chose plusieurs fois, ou de vous moquer d'une certaine manière.

Par exemple (bien que ce soit 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());
1
typoerrpr

J'ai une situation différente, je voulais me moquer d'une fonction 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(object).method(Mockito.any());
0
Mohammed Elrashidy