What is the best way to mock void methods using Mockito?

What is the best way to mock void methods using Mockito?

I am trying to mock methods that return void, but I am unsure how to do it with mockito void method.

I implemented an observer pattern, but I can’t seem to mock it correctly using Mockito. I searched for examples but didn’t find a clear solution.

Here’s my class structure:

public class World {

    List<Listener> listeners;

    void addListener(Listener item) {
        listeners.add(item);
    }

    void doAction(Action goal, Object obj) {
        setState("i received");
        goal.doAction(obj);
        setState("i finished");
    }

    private String state;
    // Setter and getter for state
}

public class WorldTest implements Listener {

    @Test
    public void testWorld() {
        World w = mock(World.class);
        w.addListener(this);
        // Test logic here
    }
}

interface Listener {
    void doAction();
}

The system does not trigger properly with mock objects. I want to observe the system state and make assertions based on those states. What is the right approach for mocking void methods in Mockito?

In Mockito, to mock void methods, you can use doNothing(), doThrow(), or doAnswer().

For your specific case, since you’re trying to observe the state change in the World class, you can use doNothing() to mock the setState() method if it has no actual side effect or if you want to avoid triggering it in the test.

Here’s how you can mock the void method setState() and test your code:

import static org.mockito.Mockito.*;

public class WorldTest {

    @Test
    public void testWorld() {
        // Mock the World class
        World w = mock(World.class);
        
        // Mock the setState method to do nothing
        doNothing().when(w).setState(anyString());

        // Add the listener and trigger the doAction method
        w.addListener(this);
        w.doAction(mock(Action.class), new Object());

        // You can now verify that setState was called with the expected values
        verify(w).setState("i received");
        verify(w).setState("i finished");
    }

    // Implement the Listener interface
    @Override
    public void doAction() {
        // Do something
    }
}

In this case, doNothing().when(w).setState(anyString()) ensures that when setState() is called inside the doAction method, it doesn’t actually modify the state, but we can still verify its behavior.

To add to @joe-elmoufak point, if your void method should throw an exception when certain conditions are met, you can use doThrow(). For example, if you expect the setState method to throw an exception when trying to set an invalid state, you can mock this behavior like so:

import static org.mockito.Mockito.*;

public class WorldTest {

    @Test(expected = IllegalArgumentException.class)
    public void testWorldWithException() {
        World w = mock(World.class);
        
        // Mocking setState to throw an exception
        doThrow(new IllegalArgumentException()).when(w).setState(anyString());

        // Triggering the action, this will now throw the exception
        w.setState("invalid state");
    }
}

This is useful when you want to simulate error scenarios in your tests.

Good insight! If you want to observe interactions and perhaps perform some custom logic when the void method is called (like updating the state or logging), you can use doAnswer() to define custom behavior for the setState() method. This allows you to capture method invocations or even mock behaviors:

import static org.mockito.Mockito.*;

public class WorldTest {

    @Test
    public void testWorldWithCustomAnswer() {
        World w = mock(World.class);

        // Using doAnswer to capture calls to setState and perform custom logic
        doAnswer(invocation -> {
            String state = invocation.getArgument(0);
            System.out.println("State is being set to: " + state);  // Custom logic or logging
            return null;  // Since setState is void, we return null
        }).when(w).setState(anyString());

        // Add listener and perform action
        w.addListener(this);
        w.doAction(mock(Action.class), new Object());

        // Verify custom logic and ensure setState was called
        verify(w).setState("i received");
        verify(w).setState("i finished");
    }

    @Override
    public void doAction() {
        // Do something for the test
    }
}

This approach is powerful because you can simulate more complex behavior and even assert that the correct parameters were passed to the setState() method.