La simulazione della prima chiamata non riesce, la seconda ha esito positivo


119

Voglio usare Mockito per testare il codice (semplificato) di seguito. Non so come dire a Mockito di fallire la prima volta, poi di farcela la seconda volta.

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

Posso impostare il test di successo con:

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

E il test di fallimento con:

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

Ma come posso verificare che se fallisce una (o due volte) e poi riesce, va bene?

Risposte:


250

Dai documenti :

A volte abbiamo bisogno di stub con un valore di ritorno / eccezione diverso per la stessa chiamata di metodo. Il caso d'uso tipico potrebbe essere quello di deridere gli iteratori. La versione originale di Mockito non aveva questa caratteristica per promuovere semplici prese in giro. Ad esempio, al posto degli iteratori si potrebbe usare Iterable o semplicemente le collezioni. Questi offrono modi naturali di stubbing (ad esempio utilizzando collezioni reali). In rari scenari potrebbe essere utile lo stubbing di chiamate consecutive:

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

Quindi nel tuo caso, vorresti:

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

25
Questo mi ha indirizzato nella giusta direzione (grazie) per il mio scenario che riguardava i metodi void - in quel caso devi usare lo stile alternativo ...doThrow(new RuntimeException()).doNothing().when(myMock).doTheCall();
haggisandchips

38

Il modo più breve per scrivere quello che vuoi è

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

Quando fornisci più argomenti in thenReturnquesto modo, ogni argomento verrà utilizzato al massimo una volta, ad eccezione dell'ultimo argomento, che viene utilizzato tutte le volte necessarie. Ad esempio, in questo caso, se effettui la chiamata 4 volte, otterrai "Riuscito", "hai fallito", "hai fallito", "hai fallito".


22

Poiché il commento relativo a questo è difficile da leggere, aggiungerò una risposta formattata.

Se stai provando a farlo con una voidfunzione che genera solo un'eccezione, seguita da un passaggio senza comportamento, allora dovresti fare qualcosa del genere:

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

4

Per aggiungere a questa e questa risposta, puoi anche utilizzare un ciclo per concatenare le chiamate derise. Questo è utile se devi deridere la stessa cosa più volte o deridere in qualche schema.

Ad esempio (anche se inverosimile):

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

In realtà non sapevo di questo Stubber e l'ho trovato utile, +1.
Mihai Morcov

Questa dovrebbe essere la risposta giusta se hai bisogno di chiamare un metodo void.
db80

4

Ho una situazione diversa, volevo deridere una voidfunzione per la prima chiamata ed eseguirla normalmente alla seconda chiamata.

Questo funziona per me:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.