doReturn-when与when-thenReturn在Mock/Spy对象中的行为差异
doReturn-when vs when-thenReturn Great question—this is a super common gotcha when working with Mockito Spies, so let’s break it down clearly.
Which One Works for Skipping Real Nested Method Calls?
Short answer: Use doReturn(...).when(spyObject).nestedMethod() if you want to avoid triggering the real execution of nested methods in your Spy.
Here’s the critical difference between the two:
when(spyObject.nestedMethod()).thenReturn(...)operates by first calling the real version ofnestedMethod()on the Spy, then replacing its return value with your mock. That means any side effects, calls to other methods, or logic inside the real nested method will still run before the mock kicks in.doReturn(...).when(spyObject).nestedMethod()skips the real method entirely. It directly tells Mockito to return your specified value whenevernestedMethod()is called, without executing a single line of the real code inside it.
Example to Make This Concrete
Let’s use a simple class where a main method calls a nested method we want to mock:
public class OrderService { public String processOrder() { // We want to mock this nested method call String inventoryStatus = checkInventory(); return "Order processed: " + inventoryStatus; } public String checkInventory() { // Real code we don't want to run in tests (e.g., database calls) System.out.println("Real inventory check ran!"); return "In Stock"; } }
Using when-thenReturn (Triggers Real Method)
@Test void testWithWhenThenReturn() { OrderService spy = Mockito.spy(new OrderService()); when(spy.checkInventory()).thenReturn("Mocked: In Stock"); String result = spy.processOrder(); // You'll see "Real inventory check ran!" printed to the console assertEquals("Order processed: Mocked: In Stock", result); }
Using doReturn-when (Skips Real Method)
@Test void testWithDoReturnWhen() { OrderService spy = Mockito.spy(new OrderService()); doReturn("Mocked: In Stock").when(spy).checkInventory(); String result = spy.processOrder(); // No "Real inventory check ran!" output—real method never executed assertEquals("Order processed: Mocked: In Stock", result); }
Other Ways to Avoid Real Method Calls in Spies
Besides doReturn, you can use other doXxx methods for different scenarios:
doThrow(new InventoryUnavailableException()).when(spy).checkInventory(): Make the nested method throw an exception without running real code.doAnswer(invocation -> "Custom Stock Status").when(spy).checkInventory(): Replace the real method with custom logic, skipping the real execution entirely.
If you find yourself needing to mock most methods of an object, consider using a full @Mock instead of a @Spy—Spies are designed for partial mocking (keeping most methods real while mocking a few), while Mocks are for full isolation. But if you must use a Spy (e.g., testing a specific method while mocking its internal dependencies), doReturn-when is your go-to tool.
内容的提问来源于stack exchange,提问作者Lahiru Pathirana

