Explain Codes LogoExplain Codes Logo

How to tell a Mockito mock object to return something different the next time it is called?

java
mockito
unit-testing
test-configuration
Nikita BarsukovbyNikita Barsukov·Jan 18, 2025
TLDR

Mockito provides a way to return sequential responses for a method, using multiple thenReturn calls:

SomeClass mock = mock(SomeClass.class); when(mock.method()).thenReturn("First").thenReturn("Second"); System.out.println(mock.method()); // Prints "First", makes us happy System.out.println(mock.method()); // Prints "Second", mind = blown

When method() is invoked, it first brofists us with "First", and then with "Second" on its next execution.

Rediscover Mockito: Customized returns, exceptions, and mirth

Implementing sequential returns

thenReturn supports varargs, allowing a sequence of values on subsequent calls:

when(mock.method()).thenReturn("First Call", "Second Call", "Hulk Smash!", "Fourth Call");

Each call brings in a new return value, sequentially. The Hulk there stands for an unexpected scenario.

Embracing exceptions in mocking

For tests that need to trigger exceptions, use thenReturn and thenThrow in tandem:

when(mock.method()).thenReturn("Good times").thenThrow(new RuntimeException());

First, it's sunshine and rainbows with "Good times". Then, turns into a scene from a scary movie with an exception.

Giving mocks a fresh perspective every time

You can certainly avoid cross-test horror by resetting your mock before each test:

@Before public void setup() { reset(mock); // Configure the mock for the next test }

Clearly, this way your tests are living in the NOW, not haunted by past states!

Steering clear of actual method calls with spies

If you’re working with spies, use doReturn() instead of when() to prevent actual method calls:

SomeClass spy = spy(new SomeClass()); doReturn("Controlled Response").when(spy).method();

It's a mock... it's a spy... it's SuperMock! Stopping actual method calls dead in their tracks!

Creating isolated test environments

Private mocks and @Before setup are your best bet for carving out individual sandboxes for your tests:

private SomeClass mock; @Before public void setup() { mock = mock(SomeClass.class); // Initialization code here }

Just like all of us yearn for our own space, each test having its mock is a thing of beauty.

Mastering Mockito: The Good, the Bad and the Best Practices

Enhancing readability with method chaining

You can keep the code clean and crisp by chaining methods. This keeps the number of statements at a minimum:

when(mock.method()) .thenReturn("First Call") .thenReturn("Second Call") .thenReturn("Third Call");

Indeed, less is better, Echoes of familiar principles, huh?

Staying away from static mocks

Static mocks are like pesky in-laws. Avoid them. They can carry unwarranted state between tests, leading to brittle tests.

Making your mocks versatile

Varied test scenarios may require a single mock to switch behaviors. By doing so, we promote code reusability and uncluttered tests.

Consistency is key

Each test should tidy up after itself using its own mock setup. This gives us predictable, reliable outputs – a thing of beauty in unit testing.

Time is money, Save it

Leveraging Mockito's method chaining can save a tonne of time on mock configuration.