204

I want to use Mockito to test the (simplified) code below. I don't know how to tell Mockito to fail the first time, then succeed the second time.

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

I can setup the success test with:

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

And the failure test with:

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

But how can I test that if it fails once (or twice) then succeeds, it's fine?

jb.
  • 9,921
  • 12
  • 54
  • 90

6 Answers6

364

From the docs:

Sometimes we need to stub with different return value/exception for the same method call. Typical use case could be mocking iterators. Original version of Mockito did not have this feature to promote simple mocking. For example, instead of iterators one could use Iterable or simply collections. Those offer natural ways of stubbing (e.g. using real collections). In rare scenarios stubbing consecutive calls could be useful, though:

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

So in your case, you'd want:

when(myMock.doTheCall())
   .thenReturn("You failed")
   .thenReturn("Success");
Charney Kaye
  • 3,667
  • 6
  • 41
  • 54
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 51
    This pointed me in the right direction (thanks) for my scenario which was dealing with void methods - in that instance you need to use the alternative style ... `doThrow(new RuntimeException()).doNothing().when(myMock).doTheCall();` – haggisandchips Sep 13 '16 at 15:04
  • 1
    I was not aware that we can mock it this way. Thank you so much Charney! This takes care of many complex scenario that we want to test. – Raj Jul 20 '22 at 19:05
55

The shortest way to write what you want is

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

When you supply mutiple arguments to thenReturn like this, each argument will be used at most once, except for the very last argument, which is used as many times as necessary. For example, in this case, if you make the call 4 times, you'll get "Success", "you failed", "you failed", "you failed".

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
54

Since the comment that relates to this is hard to read, I'll add a formatted answer.

If you are trying to do this with a void function that just throws an exception, followed by a no behavior step, then you would do something like this:

Mockito.doThrow(new Exception("MESSAGE"))
            .doNothing()
            .when(mockService).method(eq());
Ilya Serbis
  • 21,149
  • 6
  • 87
  • 74
anoneironaut
  • 1,778
  • 16
  • 28
10

I have a different situation, I wanted to mock a void function for the first call and run it normally at the second call.

This works for me:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());
Ilya Serbis
  • 21,149
  • 6
  • 87
  • 74
Mohammed Elrashidy
  • 1,820
  • 1
  • 14
  • 16
8

To add on to this and this answer, you can also use a loop to chain the mocked calls. This is useful if you need to mock the same thing several times, or mock in some pattern.

Eg (albeit a farfetched one):

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());
jb.
  • 9,921
  • 12
  • 54
  • 90
typoerrpr
  • 1,626
  • 21
  • 18
2

The shortest would be

doReturn("Fail", "Success").when(myMock).doTheCall();