javajunitmockito

Mockito: Understanding how when().thenThrow() function works


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.


Solution

  • 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.