In Mockito, the most common way to create a mock object is to use either @Mock annotation or Mockito.mock method. When a method having a return value is called for a mock object, it returns an empty value such as 0, empty collections, an empty string, and null.

@Mock
private ConnectionInfo connectionInfo;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}
private ConnectionInfo connectionInfo;

@Before
public void setUp() {
    navigator = Mockito.mock(Navigator.class);
}

When you want to change a return value for testing, you can do it with when-return. This works well if the object’s behavior is simple. However, there could be cumbersome work to write multiple when-returns if a mock object is too complex.

when(connetionInfo.isConnected()).thenReturn(true);

For those cases, Mockito supports a way to set logic for specifying what to return instead of an empty value. You can do it by implementing Answer interface and passing it when you mock an object. There are predefined Answers for common cases in Mockito. You could utilize this rather than implementing a custom Answer. Here are some useful Mockito Answers.

RETURNS_MOCKS

If a method return type is a custom class, a mock returns null because there is no empty value for a custom class. RETURN_MOCKS will try to return mocks if possible instead of null. Since final class cannot be mocked, null is still returned in that case.

public class Album {
    @NonNull private String title;
    @NonNull private Image image;
    @NonNull private List<Track> tracks;

    public Album(@NonNull Image image,
                 @NonNull String title,
                 @NonNull List<Track> tracks) {
        this.image = image;
        this.title = title;
        this.tracks = tracks;
    }

    // Getters
    @NonNull
    public Image getImage() {
        return image;
    }
    ...
}

A below example verifies a behavior by changing the getTitle(). In onDataLoaded(), the presenter accesses getImage().getUrl() to show an image. Although getTitle() is a main condition to verify, there is an additional when-return to avoid a null pointer exception.

@Test
public void test() {
    Album album = mock(Album.class);
    when(album.getTitle()).thenReturn("TITLE");
    when(album.getImage()).thenReturn(mock(Image.class)); // Note: Need to avoid NPE

    // This accesses `getImage().getUrl()`
    presenter.onDataLoaded(album);

    verify(viewBinder).showTitle("TITLE");
}

With RETURNS_MOCKS, this test could be simplified. You don’t need to set up additional when-return since a mock is returned.

@Test
public void test() {
    Album album = mock(Album.class, Answers.RETURNS_MOCKS);
    when(album.getTitle()).thenReturn("TITLE");

    presenter.onDataLoaded(album);

    verify(viewBinder).showTitle("TITLE");
}

When you use an annotation, you can specify Answer like below.

@Mock(answer = Answers.RETURNS_MOCKS)
private Album album;

RETURNS_SELF

This uses the return type of a method. If that type equals to the class or a superclass, it will return the mock. This is especially useful for builder classes. You don’t need to implement when-return for builder methods.

public  class HttpBuilder {

    private String uri;
    private List<String> headers;

    public HttpBuilder() {
        this.headers = new ArrayList<>();
    }

    public HttpBuilder withUrl(String uri) {
        this.uri = uri;
        return this;
    }

    public HttpBuilder withHeader(String header) {
        this.headers.add(header);
        return this;
    }

    public String request() {
        return uri + headers.toString();
    }
}

public class HttpRequesterWithHeaders {

    private HttpBuilder builder;

    public HttpRequesterWithHeaders(HttpBuilder builder) {
        this.builder = builder;
    }

    public String request(String uri) {
        return builder.withUrl(uri)
                .withHeader("Content-type: application/json")
                .withHeader("Authorization: Bearer")
                .request();
    }
}

You can see there are two when-returns to mock a builder properly.

@Test
public void test() {
    HttpBuilder builder = mock(HttpBuilder.class);
    when(builder.withUrl(anyString())).thenReturn(builder); // Note: Need to avoid NPE
    when(builder.withHeader(anyString())).thenReturn(builder); // Note: Need to avoid NPE
    HttpRequesterWithHeaders requester = new HttpRequesterWithHeaders(builder);
    String request = "REQUEST_URI";

    when(builder.request()).thenReturn(request);

    assertThat(requester.request("URI")).isEqualTo(request);
}

When RETURNS_SELF is set, the mock is returned when it is assignable. Thus, you don’t need to set up manually. Note that the mock is returned when the return type is Object. Object is a superclass of the class.

@Test
public void test() {
    HttpBuilder builder = mock(HttpBuilder.class, Answers.RETURNS_SELF);
    HttpRequesterWithHeaders requester = new HttpRequesterWithHeaders(builder);
    String request = "REQUEST_URI";

    when(builder.request()).thenReturn(request);

    assertThat(requester.request("URI")).isEqualTo(request);
}

RETURNS_DEEP_STUBS

When a class refers to another class, you sometimes have a chain of methods to get a value. This chain could be deep and multiple levels. For mocking them, you need to return a mock which returns a mock. For example, there are several when-returns because of a deep chain.

@Test
public void test() {
    Artist artist = Mockito.mock(Artist.class);
    Album album = mock(Album.class);
    Track track = mock(Track.class);
    when(artist.getLatestAlbum()).thenReturn(album);
    when(album.getTracks()).thenReturn(Lists.newArrayList(track));
    when(track.getTitle()).thenReturn("TITLE");

    assertEquals("TITLE", artist.getLatestAlbum().getTracks().get(0).getTitle());
}

RETURNS_DEEP_STUBS makes it possible to set up a return value for a chain of methods without setting mocks between a chain. Thus, you can shortly set it like below.

@Test
public void test() {
    Artist artist = Mockito.mock(Artist.class, Answers.RETURNS_DEEP_STUBS);
    when(artist.getLatestAlbum().getTracks().get(0).getTitle()).thenReturn("TITLE");

    assertEquals("TITLE", artist.getLatestAlbum().getTracks().get(0).getTitle());
}

Conclusion

Mockito Answer supports a custom logic to return a value instead of a literal value. If you have multiple when-thens before verifying, consider using predefined Mockito Answers. Otherwise, you can create your own Answer to simplify setup and focus on verification.