Explain Codes LogoExplain Codes Logo

How to mock void methods with Mockito

java
mockito
testing
unit-testing
Alex KataevbyAlex Kataev·Sep 9, 2024
TLDR

To mock a void method with Mockito, you can use doNothing() for no action, doThrow() to simulate exceptions, or doAnswer() for custom actions. Implement them prior to the when() method to configure behavior.

Mockito.doNothing().when(mockedObject).voidMethod(); // chill, do nothing // or Mockito.doThrow(new Exception()).when(mockedObject).voidMethod(); // Oops, we got an accident // or Mockito.doAnswer(invocation -> { /* custom actions */ return null; }).when(mockedObject).voidMethod(); // Let's get creative!

When to mock void methods?

At times, mocking void methods seems like trying to listen to a silent song - why do it? Imagine a method that sends an email. During testing, you don't need real emails flying around. But you do need to ensure that the "SendEmail" method was called. That's where doNothing(), doThrow(), and doAnswer() step in.

Handling logical complexity

What if the void method has intricate logic or multiple arguments? Use Answer interface:

doAnswer((InvocationOnMock invocation) -> { Object arg0 = invocation.getArgument(0); // Handle complex situations like defusing a bomb with multiple wires return null; // Still a void method, no wire-cutting consequences }).when(mockedObject).complexBombDefusal(any());

Introducing spies: agents of Mock-land

What if you need only certain behaviors of an object to be mocked and get the rest of the original functionality? Dial Mockito.spy():

List<String> list = new ArrayList<>(); List<String> spyList = Mockito.spy(list); // The spy keeps an eye on our `clear()` method and neutralizes its behavior doNothing().when(spyList).clear(); // Here, `add()` continues with its vanilla behavior spyList.add("Mockito, shaken not stirred");

Chain behavior and verification: keep the naughty methods in check

To impose different behaviors on methods called in sequence, chain doThrow() and doNothing():

doThrow(new IllegalStateException()) // First attempt: Fails, tough life! .doNothing() // Second attempt: Success, well, sort of ... .when(mockedObject).voidMethod(); // Now, cross-verify the call count verify(mockedObject, times(2)).voidMethod();

For asserting the behavior, use Mockito.verify(). It's like being the detective on the void-method crime scene:

verify(mockedObject).voidMethod(); // With argument matchers, it's like a polygraph test verify(mockedObject).voidMethodWithArgs(argThat(someCondition));

Isolating tests: Insulate from void method radiations

Your tests need isolation. Imaging there's a radiation-leaking methodWithSideEffects():

doAnswer(invocation -> { // No mutation-causing state changes in the mock return null; }).when(mockedObject).methodWithSideEffects();

We obtain insulation from the radiation ... I mean, side effects.

Keep your unit test house tidy

Import Mockito's static methods:

import static org.mockito.Mockito.*; // You can make your test code more concise: doNothing().when(spyList).clear();