1. Overview
Mockito is a widely used unit testing framework for Java applications. It provides various APIs to mock the behavior of objects. In this tutorial, we’ll explore the usage of doAnswer() and thenReturn() stubbing techniques, and compare them. We can use both APIs for stubbing or mocking methods, but in some cases, we can only use one.
2. Dependencies
Our code will use Mockito in combination with JUnit 5 for our code examples, and we need to add a few dependencies to our pom.xml file:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
We can find the JUnit 5 API library, the JUnit 5 Engine library, and the Mockito library in the Maven Central repository.
3. Stubbing Methods Using thenReturn()
We can use the thenReturn() stubbing technique in Mockito to stub methods that return a value. To demonstrate, we’ll test the get() and add() operations of a list using thenReturn() and doAnswer():
public class BaeldungList extends AbstractList<String> {
@Override
public String get(final int index) {
return null;
}
@Override
public void add(int index, String element) {
// no-op
}
@Override
public int size() {
return 0;
}
}
In the sample code above, the get() method returns a String. First, we’ll stub the get() method using thenReturn() and validate the invocation by asserting its return value is the same as the stubbed method:
@Test
void givenThenReturn_whenGetCalled_thenValue() {
BaeldungList myList = mock(BaeldungList.class);
when(myList.get(anyInt()))
.thenReturn("answer me");
assertEquals("answer me", myList.get(1));
}
3.1. Stubbing Methods to Return Multiple Values Using thenReturn()
In addition to this, the thenReturn() API allows returning different values in consecutive calls. We can chain its invocations to return multiple values. Moreover, we can pass multiple values in a single method call:
@Test
void givenThenReturn_whenGetCalled_thenReturnChaining() {
BaeldungList myList = mock(BaeldungList.class);
when(myList.get(anyInt()))
.thenReturn("answer one")
.thenReturn("answer two");
assertEquals("answer one", myList.get(1));
assertEquals("answer two", myList.get(1));
}
@Test
void givenThenReturn_whenGetCalled_thenMultipleValues() {
BaeldungList myList = mock(BaeldungList.class);
when(myList.get(anyInt()))
.thenReturn("answer one", "answer two");
assertEquals("answer one", myList.get(1));
assertEquals("answer two", myList.get(1));
}
4. Stubbing void Methods Using doAnswer()
The add() method is a void method and does not return anything. We can’t stub the add() method with thenReturn() as the thenReturn() stubbing can’t be used with void methods. Instead, we’ll use doAnswer() as it allows the stubbing of void methods. So, we’ll stub the add() method using doAnswer(), and the Answer provided in the stub is invoked when the add() method is called:
@Test
void givenDoAnswer_whenAddCalled_thenAnswered() {
BaeldungList myList = mock(BaeldungList.class);
doAnswer(invocation -> {
Object index = invocation.getArgument(0);
Object element = invocation.getArgument(1);
// verify the invocation is called with the correct index and element
assertEquals(3, index);
assertEquals("answer", element);
// return null as this is a void method
return null;
}).when(myList)
.add(any(Integer.class), any(String.class));
myList.add(3, "answer");
}
In the doAnswer(), we validate that the invocation to the add() method is called, and we assert the parameters it’s called with are as expected.
4.1. Stubbing Non-void Methods Using doAnswer()
Since we can stub methods with an Answer that returns a value instead of null, we can use the doAnswer() method to stub non-void methods. For example, we’ll test the get() method by stubbing it with doAnswer() and returning an Answer that returns a String:
@Test
void givenDoAnswer_whenGetCalled_thenAnswered() {
BaeldungList myList = mock(BaeldungList.class);
doAnswer(invocation -> {
Object index = invocation.getArgument(0);
// verify the invocation is called with the index
assertEquals(1, index);
// return the value we want
return "answer me";
}).when(myList)
.get(any(Integer.class));
assertEquals("answer me", myList.get(1));
}
4.2. Stubbing Methods to Return Multiple Values Using doAnswer()
We must note that we can only return one Answer in the doAnswer() method. However, we can put conditional logic in the doAnswer() method that returns different values based on the arguments received by the invocation. So, in the sample code below, we’ll return different values depending on the index we call the get() method with:
@Test
void givenDoAnswer_whenGetCalled_thenAnsweredConditionally() {
BaeldungList myList = mock(BaeldungList.class);
doAnswer(invocation -> {
Integer index = invocation.getArgument(0);
switch (index) {
case 1:
return "answer one";
case 2:
return "answer two";
default:
return "answer " + index;
}
}).when(myList)
.get(anyInt());
assertEquals("answer one", myList.get(1));
assertEquals("answer two", myList.get(2));
assertEquals("answer 3", myList.get(3));
}
5. Conclusion
The Mockito framework provides many stubbing/mocking techniques such as doAnswer(), doReturn(), thenReturn(), thenAnswer(), and many more to facilitate various types and styles of Java code and its testing. We have used the doAnswer() and the thenReturn() to stub non-void methods and perform similar tests. However, we can only use doAnswer() to stub a void method, as the thenReturn() method is unable to perform this function. As usual, all of our code samples are available over on GitHub.