Mockito thenReturn() vs thenAnswer()

Mockito is a very powerful test library for Java. In most cases, setting some mock action with thenReturn() is enough. But in some rare cases, we need to use thenAnswer().

thenReturn() example

First, let’s review the basic use of thenReturn()

public class TestTargetClass {
	public String getResultWithParam(int param) {
		return null;
	}

	public String getResultWithoutParam() {
		return null;
	}
}

First, I want to test getResultWithParam().

	@Test
	public void testGetResultWithParam() throws Exception{
		TestTargetClass testTarget = mock(TestTargetClass.class);
		when(testTarget.getResultWithParam(1)).thenReturn("A");
		when(testTarget.getResultWithParam(2)).thenReturn("B");
		when(testTarget.getResultWithParam(3)).thenReturn("C");
		assertEquals("A", testTarget.getResultWithParam(1));
		assertEquals("B", testTarget.getResultWithParam(2));
		assertEquals("C", testTarget.getResultWithParam(3));
	}

Above test case succeeds.

Wrong test case

Next, I want to test getResultWithoutParam(). In this case, I want to check the return value depending on some outer context. So I try the following test case.

	private String result;

	// Wrong test
	@Test
	public void testGetResultWithoutParam() throws Exception{
		TestTargetClass testTarget = mock(TestTargetClass.class);
		when(testTarget.getResultWithoutParam()).thenReturn(result);
		this.result = "A";
		assertEquals("A", testTarget.getResultWithoutParam());
		this.result = "B";
		assertEquals("B", testTarget.getResultWithoutParam());
		this.result = "C";
		assertEquals("C", testTarget.getResultWithoutParam());
	}

I expected that getResultWithoutParam() would return result‘s value. But
it failed at the first asserEquals() with the following message.

java.lang.AssertionError: expected:<A> but was:

This error occurs because result is bound statically when thenReturn() is called.

Right test case – thenAnswer()

The solution is to use thenAnswer().

	private String result;

	// Right test
	@Test
	public void testGetResultWithoutParam() throws Exception{
		TestTargetClass testTarget = mock(TestTargetClass.class);
		when(testTarget.getResultWithoutParam()).thenAnswer(new Answer() {
			public String answer(InvocationOnMock invocation) throws Throwable{
				return result;
			}
		});
		this.result = "A";
		assertEquals("A", testTarget.getResultWithoutParam());
		this.result = "B";
		assertEquals("B", testTarget.getResultWithoutParam());
		this.result = "C";
		assertEquals("C", testTarget.getResultWithoutParam());
	}

Above code succeeds because whenever getResultWithoutParam() is called, a new Answer object is created and it returns result’s value.

Conclusion

To sum up, thenReturn() is enough when result is dependent on the param. But thenAnswer() is necessary when different results need to be tested depending on the other context.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.