Explain Codes LogoExplain Codes Logo

Using Mockito with multiple calls to the same method with the same arguments

java
mockito
testing
stubbing
Nikita BarsukovbyNikita Barsukov·Sep 7, 2024
TLDR

If you want an identical method to have different outcomes per call with Mockito, use thenReturn consecutively:

when(mockedObject.someMethod("arg")).thenReturn(value1, value2, value3);

For flexibility and logic-based processing, combine thenReturn and thenAnswer:

when(mockedObject.someMethod("arg")).thenReturn(value1).thenAnswer(invocation -> dynamicValue);

Each call retrieves the next value, allowing dynamic behaviors.

Advanced usage of Mockito stubbing

To stretch Mockito to its full potential and simulate more intricate scenarios:

Use Answer for customized behavior

If you want your test to feel alive and change its behavior based on context or even remember past decisions, use the Answer interface:

when(mockedObject.someMethod(anyString())).thenAnswer(new Answer<String>() { private int callCount = 0; // I remember everything!👀 public String answer(InvocationOnMock invocation) { if (callCount == 0) { callCount++; // One more to my tally! return "Fresh response served!"; } else if (callCount == 1) { callCount++; // Counting like a pro! return "Leftover response, still delicious!"; } else { return "Sorry, only default response available!"; } // Looks like someone's a picky eater!😁 } });

Control varied responses for successive calls

If you want to spice up your test's life with a little drama by having different behaviors & even throw exceptions on each call:

when(mockedObject.someMethod("arg")) .thenReturn("First call: innocent!") .thenReturn("Second call: suspicious!") .thenThrow(new RuntimeException("Third call: you're busted!")); // Seems like this test got into trouble!😈

Testing void methods with doReturn

In the rare case of testing void methods or spies without the actual method getting triggered:

doReturn(null).doThrow(new RuntimeException()).when(spyOrVoidMethod).performAction(); // "It's a trap!" Acted smart, didn't you? 😎

Cool, huh? It prevents a spy from acting on its own while controlling its behavior.

Use BDD style stubbing with Mockito

The Behavior-Driven Development (BDD) style offers readable structuring for stubbing. Mockito heartily supports this with the BDDMockito class.

Clear structuring with BDD

Give clear instructions to your mock with exact method call scenarios:

BDDMockito.given(mockedObject.someMethod("expected argument")) .willReturn("fresh response") .willReturn("reheated response") .willThrow(IllegalStateException.class); // "I took a chance... It was a calculated risk, but man, I am bad at math." 😂

Runtime dynamic stubs with willAnswer

Create mocks that play along with the application behaviour, not against it:

BDDMockito.willAnswer(invocation -> { Object arg = invocation.getArgument(0); return "Responding to " + arg; }).given(mockedObject).someMethod(any()); // "I am like a chameleon, always a step ahead of your actions." 😂

These mocks can react to arguments dynamically, giving a mirror-like reflection of the real application.