Mockito when-then vs do-when

Writing unit test is very important for better software quality. For unit tests Mockito is one of the most common choices of developers. Mockito providers different way to mock methods, like do...when and when..then. Most of the time we face the question to use when-then vs do-when. We will see all the differences in detail.

In Mockito we can mock methods in 2 different ways,

DatabaseService service = Mockito.mock(DatabaseService.class);
when(service.isConnected()).thenReturn(true);
doReturn(true).when(service.isConnected())

Different methods for do-when

  • doNothing()
  • doReturn(Object toBeReturned)
  • doReturn(Object toBeReturned, Object… toBeReturnedNext)
  • doAnswer(Answer answer)
  • doCallRealMethod()
  • doThrow(Throwa=le… ToBeThrown)
  • doThrow(Class toBeThrown)
  • doThrow(Class toBeThrown, Class… toBeThrownNext)

Different methods for when-then

  • thenReturn(T var1)
  • thenReturn(T var1, T… var2)
  • thenAnswer(Answer var1)
  • then(Answer var1)
  • thenCallRealMethod()
  • thenThrow(Throwable… var1)
  • thenThrow(Class var1)
  • thenThrow(Class var1, Class… var2)

Recommended difference between thenReturn and thenAnswer in mockito

In most cases when-then is used because it provides more readability, however there are some cases, where both approaches behave differently and should be used carefully.

  1. Return type validation in mocking
  2. Mocking methods of spy objects
  3. Mocking void methods

Return type validation for mocked object

Return type of doReturn(..) is Object whereas the return type of thenReturn(..) is as per the method type. So in case of doReturn we might get org.mockito.exceptions.misusing.WrongTypeOfReturnValue exception if incompatible return value is used. In case of thenReturn, if we use wrong value the application won't compile.

List<String> mockedList = Mockito.mock(ArrayList.class);
Mockito.when(mockedList.size()).thenReturn("test");

This will give compile time error, hence easy to fix.

List<String> mockedList = Mockito.mock(ArrayList.class);
doReturn("Test").when(mockedList).size();

This will compile but fail at runtime.

For mocked objects it is best practice to use when-then option as it provides return type checking and it is more readability. However it has drawbacks in case of spied objects and void methods.

Mocking methods of spy object

Spy objects are linked to the actual objects, where we dont have to mock all the methods. And actual method calls are made for the methods that are not mocked.
For mocked object all the methods are mocked, and there we dont need real objects.

Mockito mocking method with when-then approach

When we are using mock, first we need to create mocked object. Then we specify what should be returned using when-then. In that case it don’t do anything with real class.

List<string> mockedList = Mockito.mock(List.class);

Mockito.when(mockedList.get(0)).thenReturn("Test");

assertEquals("Test", mockedList.get(0));

When we are using spy, as it is linked to real object, when we use when(spyobject.method()).thenReturn(value), the real method on spied object is called. Even when we try to mock the behavior.

Spy mocking method using when-then approach

If we mock method on spied object using when-then, real method is called but mocked value is returned. This could cause exception as some fields might be null.

List<string> spiedList = Mockito.spy(List.class);

Mockito.when(mockedList.get(0)).thenReturn("Test");

Real method get(0)is called on list and this throws java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

The correct way to fix this issue is to use doReturn-when

List<String> spiedList = Mockito.spy(ArrayList.class);
Mockito.doReturn("Test").when(spiedList).get(0);
assertEquals("Test", spiedList.get(0));

Note: Real method is called only for spy class objects not for spy Interfaces.

Following code works fine as we are using Interface for spy not the object.

List<String> spiedList = Mockito.spy(List.class);
Mockito.when(spiedList.get(0)).thenReturn("Test");

Mocking void method

Mocking void method is different than other methods. For mocking void method, there is no when-then option. We have to use do-when option.

Example of mocking

List<String> mockedList = Mockito.mock(List.class);
Mockito.doNothing().when(mockedList).clear();

Example of Spy

List<String> spiedList = Mockito.spy(ArrayList.class);
spiedList.add("Test"); 
Mockito.doNothing().when(spiedList).clear(); 
spiedList.clear(); 
assertEquals("Test", spiedList.get(0));

Fast track reading

  • In Mockito method are mocked using 'when-then' or 'do-when'
  • In most cases when-then is used because it provides more readability with return type validation
  • Mocking methods of spy object using 'when-then' option could lead to exception hence 'do-when' option must be used
  • For mocking void methods there is no 'when-then' option
  • Real method of spy object is called if when-then option is used for mocking the method, however the mocked value is returned

Reference

Related Topics:

Leave a Reply

Your email address will not be published. Required fields are marked *