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.