How to specify return value from a method using Mockito

Mockito allows you to specify what to return when a method is called on a mocked object. Mockito supports two ways to do it: `when-thenReturn` and `doReturn-when`. In most cases, `when-thenReturn` is used and has better readability.

Below is the example usage for testing our UserService class that has dependency on UserRepository class.

UserServiceReturnOptionsTest
/**
 * Test class to show example implementation of when-thenReturn and doReturn-when pattern of Mockito to define return
 * types from a mocked method.
 */
class UserServiceReturnOptionsTest {

    /**
     * This method used when-thenReturn pattern to set return value from a mock object
     */
    @Test
    void when_then_example() {
        // Create a mock object for dependency class
        UserRepository mockUserRepository = Mockito.mock(UserRepository.class);

        // Add mocked dependency to the class object being tested
        UserService userService = new UserService(mockUserRepository);

        // Use when-thenReturn format to specify return value for invoked method on mock
        Mockito.when(mockUserRepository.findById(100L)).thenReturn(Optional.of(new User(100L)));

        // Invoke the method to be tested
        Optional<User> userOptional = userService.findById(100L);

        // Check return value is as expected
        Assertions.assertTrue(userOptional.isPresent());
        Assertions.assertEquals(100L, userOptional.get().getId());
    }

    /**
     * This method used doReturn-when pattern to set return value from a mock object
     */
    @Test
    void doReturn_when_example() {
        // Create a mock object for dependency class
        UserRepository mockUserRepository = Mockito.mock(UserRepository.class);

        // Add mocked dependency to the class object being tested
        UserService userService = new UserService(mockUserRepository);

        // Use doReturn-when format to specify return value for invoked method on mock
        Mockito.doReturn(Optional.of(new User(200L))).when(mockUserRepository).findById(200L);

        // Invoke the method to be tested
        Optional<User> userOptional = userService.findById(200L);

        // Check return value is as expected
        Assertions.assertTrue(userOptional.isPresent());
        Assertions.assertEquals(200L, userOptional.get().getId());
    }
}

In the above example we can see that both the patterns are very similar. But each has its own advantage. 

The `when-thenReturn` has the advantage of compile time type checking, whereas `doReturn-when` does not.  That means if we specify wrong return type as part of thenReturn() method, we would get a compile time error. Where as a wrong return type in doReturn() will fail only at runtime.

// won't compile
Mockito.when(mockUserRepository.findById(100L)).thenReturn(true);

// Will compile successfully but fail during execution of test.
Mockito.doReturn(true).when(mockUserRepository).findById(200L);


The when() method in `when-thenReturn` ends up invoking the method passed to it i.e. `mockUserRepository.findById(100L)` in example above. This is not a problem when we are using a mock object, since all its method have empty implementation. But this becomes a problem if we use `when-thenReturn` on a spy object created using `Mockito.spy()` method. In that case all the methods retain their actual implementation unless an expectation is defined for them.

The `doReturn-when` pattern is the preferred choice when specifying expectation on a spy object.

// will execute original method, hence can generate error
Mockito.when(mockUserRepository.findById(100L)).thenReturn(Optional.of(new User(200L)));

// Does not execute original method, hence no side effects.
Mockito.doReturn(Optional.of(new User(200L))).when(mockUserRepository).findById(200L);


0 comments:

Post a Comment