4
when(mockObj.method(param1, param2)).thenReturn(1);
when(mockObj.method(param1, param2)).thenReturn(2);

When there are conflicting statements to return the value from a method with same argument list in a mocked object, I observed that the recent when/thenReturn will be returned. So, the below statement will be true.

assertEquals(2, mockObj.method(param1, param2));

When there are conflicting statements to throw exceptions, the behavior is not the same as above. For example,

@Test(expected = ExceptionTwo.class)
public void testMethod() {
    when(mockObj.method(param1, param2)).thenThrow(ExceptionOne.class);
    when(mockObj.method(param1, param2)).thenThrow(ExceptionTwo.class);
    mockObj.method(param1, param2);
}

This test case failed. Any explanation would be helpful.

Will_of_fire
  • 1,089
  • 4
  • 12
  • 24
  • https://stackoverflow.com/questions/31512245/calling-mockito-when-multiple-times-on-same-object This seems to provide a few more insights along with the answers given below!! – Will_of_fire Nov 06 '17 at 14:35

2 Answers2

6

In the first case, as the document referred here:

Warning : if instead of chaining .thenReturn() calls, 
multiple stubbing with the same matchers or arguments is used, 
then each stubbing will override the previous one.

So the second will override the first one. Hence, return 2. In other case, you can refer here:

when(mock.foo()).thenThrow(new RuntimeException());

//Impossible: the exception-stubbed foo() method is called so RuntimeException is thrown.
when(mock.foo()).thenReturn("bar");

//You have to use doReturn() for stubbing:
doReturn("bar").when(mock).foo();

When you use when..thenReturn, the stubbed method will be called. The first time you didn't observe it because it is called on the mocked object. But when you write when for the second time, then we have some behavior for mock.foo() (you set it previously to throw Exception). Hence, the second when(..) statement throws the exception in your case. So you should use doThrow().when(..).method(...) instead.

Daniel Tran
  • 6,083
  • 12
  • 25
  • 1
    For the second part of the question, you said when(..).thenReturn actually calls the method. I think it is only true for spy objects and not for mocked objects (using mock). – Will_of_fire Nov 06 '17 at 14:13
2

The first example is as per design, you can refer to the below link for more details.

https://static.javadoc.io/org.mockito/mockito-core/2.11.0/org/mockito/Mockito.html#stubbing_consecutive_calls

In the second example, the exception was raised while trying to register for stub one more time when(mockObj.method(param1,param2)).thenThrow(ExceptionTwo.class);. Kindly note that it's not due to statement mockObj.method(param1, param2);.

In my opinion, there might be actual method call while second when.thenThrow statement is executed. If you want to have different exceptions for subsequent calls, you can merge into one statement when(mockObj.method(param1, param2)).thenThrow(ExceptionOne.class, ExceptionTwo.class);

sayboras
  • 4,897
  • 2
  • 22
  • 40
  • Thanks for identifying that it's the second throw statement which is actually throwing the exception in the first when(..).thenThrow() statement. – Will_of_fire Nov 06 '17 at 14:21