Mockito - difference between doReturn() and when()
Categories:
Mockito: Understanding the Nuances of doReturn() vs. when()

Explore the key differences between Mockito's doReturn()
and when()
methods for stubbing, and learn when to use each for robust unit testing.
Mockito is a popular mocking framework for Java that allows you to create mock objects for unit testing. Two of its most frequently used methods for stubbing behavior are when()
and doReturn()
. While they often achieve similar results, understanding their subtle differences and specific use cases is crucial for writing effective and maintainable tests. This article will delve into these distinctions, providing practical examples and best practices.
The 'when().thenReturn()' Approach
The when().thenReturn()
syntax is the most common and idiomatic way to stub method calls in Mockito. It reads very naturally, almost like plain English: "When this method is called with these arguments, then return this value." This approach is generally preferred for its readability and simplicity.
import static org.mockito.Mockito.*;
import java.util.List;
public class WhenExample {
public static void main(String[] args) {
List<String> mockedList = mock(List.class);
// Stubbing using when().thenReturn()
when(mockedList.get(0)).thenReturn("first");
when(mockedList.size()).thenReturn(100);
System.out.println(mockedList.get(0)); // Output: first
System.out.println(mockedList.size()); // Output: 100
// Verify interactions
verify(mockedList).get(0);
verify(mockedList).size();
}
}
Basic stubbing with when().thenReturn()
when().thenReturn()
syntax is generally recommended for most stubbing scenarios due to its readability and fluent API.The 'doReturn().when()' Approach
The doReturn().when()
syntax is an alternative way to stub methods, often referred to as the 'do-style' stubbing. While less common for simple cases, it becomes indispensable in specific scenarios where when().thenReturn()
falls short or leads to undesirable side effects. Its primary advantage lies in its ability to handle methods that might execute code before the stubbing is applied, or when dealing with void
methods.
import static org.mockito.Mockito.*;
import java.util.List;
public class DoReturnExample {
public static void main(String[] args) {
List<String> mockedList = mock(List.class);
// Stubbing using doReturn().when()
doReturn("second").when(mockedList).get(1);
doReturn(200).when(mockedList).size();
System.out.println(mockedList.get(1)); // Output: second
System.out.println(mockedList.size()); // Output: 200
// Verify interactions
verify(mockedList).get(1);
verify(mockedList).size();
}
}
Basic stubbing with doReturn().when()
Key Differences and Use Cases
The fundamental difference between when().thenReturn()
and doReturn().when()
lies in the order of execution and how Mockito handles the method call being stubbed. This difference becomes critical in several scenarios:
flowchart TD A["Stubbing Method Call"] --> B{Method Call Executes Before Stubbing?} B -- Yes --> C["Original Method Called (Potential Side Effects)"] C --> D["Use doReturn().when()"] B -- No --> E["Method Call Does Not Execute Before Stubbing"] E --> F["Use when().thenReturn()"] D --> G["Avoids Real Method Execution"] F --> H["More Readable for Simple Cases"] G & H --> I["Effective Stubbing"]
Decision flow for choosing between doReturn().when()
and when().thenReturn()
when().thenReturn()
with methods that return void
will result in a compilation error. For void
methods, you must use doNothing().when()
or doThrow().when()
.1. Stubbing Methods That Throw Exceptions
When you want a method to throw an exception, when().thenThrow()
is the direct counterpart to when().thenReturn()
. Similarly, doThrow().when()
is the do-style equivalent.
import static org.mockito.Mockito.*;
import java.util.List;
public class ExceptionStubbing {
public static void main(String[] args) {
List<String> mockedList = mock(List.class);
// Using when().thenThrow()
when(mockedList.get(0)).thenThrow(new IndexOutOfBoundsException("Index 0 is out of bounds"));
// Using doThrow().when()
doThrow(new IllegalArgumentException("Invalid argument")).when(mockedList).clear();
try {
mockedList.get(0);
} catch (IndexOutOfBoundsException e) {
System.out.println("Caught: " + e.getMessage());
}
try {
mockedList.clear();
} catch (IllegalArgumentException e) {
System.out.println("Caught: " + e.getMessage());
}
}
}
Stubbing exceptions with both when().thenThrow()
and doThrow().when()
2. Stubbing void
Methods
This is a critical distinction. when()
expects a return value, so it cannot be used directly with void
methods. For void
methods, you must use the 'do-style' methods like doNothing().when()
or doThrow().when()
.
import static org.mockito.Mockito.*;
import java.util.List;
public class VoidMethodStubbing {
public static void main(String[] args) {
List<String> mockedList = mock(List.class);
// Correct way to stub a void method to do nothing
doNothing().when(mockedList).clear();
// Correct way to stub a void method to throw an exception
doThrow(new RuntimeException("Clear failed!")).when(mockedList).add(anyString());
mockedList.clear(); // This call will do nothing
System.out.println("List cleared (no exception).");
try {
mockedList.add("item"); // This call will throw an exception
} catch (RuntimeException e) {
System.out.println("Caught: " + e.getMessage());
}
verify(mockedList).clear();
verify(mockedList).add("item");
}
}
Stubbing void
methods using doNothing()
and doThrow()
3. Stubbing Spy Objects (Partial Mocks)
When working with spy
objects (partial mocks), doReturn().when()
is often preferred. A spy
wraps a real object, and by default, calls its real methods. If you use when(spy.someMethod()).thenReturn(value)
and someMethod()
has side effects or throws an exception when called, that real method will be executed before Mockito applies the stubbing. doReturn().when(spy).someMethod()
ensures that the real method is not called when setting up the stub.
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.List;
public class SpyStubbing {
public static void main(String[] args) {
List<String> realList = new ArrayList<>();
List<String> spiedList = spy(realList);
// Incorrect for methods with side effects or exceptions:
// when(spiedList.get(0)).thenReturn("mocked"); // This would call realList.get(0) which throws IndexOutOfBoundsException
// Correct way to stub a spy:
doReturn("mocked").when(spiedList).get(0);
System.out.println(spiedList.get(0)); // Output: mocked
verify(spiedList).get(0);
}
}
Stubbing a spy object to avoid real method execution
spy
objects, always use doReturn().when()
to prevent the real method from being invoked during stubbing setup, especially if the real method has side effects or throws exceptions.Summary and Best Practices
Choosing between when().thenReturn()
and doReturn().when()
boils down to understanding their execution order and suitability for different scenarios. Here's a quick recap and some best practices:
graph TD A["Start: Choose Stubbing Style"] B{"Is it a void method?"} C{"Is it a spy object?"} D{"Does the real method have side effects or throw exceptions during stubbing?"} E["Use doNothing()/doThrow().when()"] F["Use doReturn().when()"] G["Use when().thenReturn()"] H["End: Stubbing Applied"] A --> B B -- Yes --> E B -- No --> C C -- Yes --> D D -- Yes --> F D -- No --> G C -- No --> G E --> H F --> H G --> H
Decision tree for selecting the appropriate Mockito stubbing method
In conclusion, while when().thenReturn()
is the default and most readable choice for most stubbing needs, doReturn().when()
and its do-style
counterparts provide essential flexibility for void
methods, spy
objects, and situations where preventing real method execution during stubbing is crucial. By understanding these distinctions, you can write more robust and reliable unit tests with Mockito.