Mastodon

Spying with Mockito - to call or not to call a method

The other day a weird feature of the testing library Mockito tricked me. Allthough the behavior is mentioned in the documentation, it can not be bad to point it out here. Maybe this article spares someone’s time debugging his code.

I wanted to write a unit test for the class Controller. Controller uses a method of Blo, a Business Logic Object, to perform its tasks:

public class Controller {

    Blo blo;
    
    public Controller(Blo blo) {
        this.blo = blo;
    }
    
    public int run() {
    
        // do important stuff here
    
        return blo.doSomeStuff();
    }
}
public class Blo {

    public int doSomeStuff() {
        System.out.println("doSomeStuff() was called!");
        return 42;
    }
    
    // other important methods
}

To unit-test run() in Controller, I have to decouple it from the real Blo. Otherwise the test would be an integration test instead of a unit test because Blo is also tested. Further, I want Blo to behave normally except for the one method I need for my test. That so called partial mocking can be done using Mockitos spy- method:

public class ControllerTest {

@Test
public void testStart() throws Exception {
    final Blo bloMock = spy(new Blo());
    
    // mocking methods of the spy will be done here in just a moment ...
    
    Controller s = new Controller(bloMock);
    
    assertEquals(1, s.run());
}
}

So here is where I tricked myself. There are two ways to mock the method doSomeStuff() to return a 1 instead of the only true answer 42:

when(bloMock.doSomeStuff()).thenReturn(1);

and

doReturn(1).when(bloMock).doSomeStuff();

The very important difference is that the first option will actually call the doSomeStuff()- method while the second will not. Both will cause doSomeStuff() to return the desired 1.

So, why is this important? Imagine you have some side effects in doSomeStuff() that should not be called when your test is executed. That could be the reason why you mocked it in the first place. In my example code, that side effect is just printing a message, but it could be an important state change, the change of another class or whatever.

I hope some people can save time tracking that behavior by reading this article and remembering the difference between the two options.