Mock final classes with Mockito

mock final classes with Mockito 2One of the standard Mockito related questions I’ve come across is online is “Can we mock final classes with Mockito?”. The answer to this question since Mockito 2 was introduced is “Yes, we can.”.

Example code

This is the test I would like to be able to run:

@ExtendWith(MockitoExtension.class)
class PersonTest {

    @Mock
    PinProvider pinProvider;

    @Test
    public void shouldCreatePersonWithCorrectPin() {
        String samplePin = "samplePin";
        when(pinProvider.getPin()).thenReturn(samplePin);

        Person person = new Person("Star", "Lord", pinProvider);
        assertThat(person.getPin()).isEqualTo(samplePin);
    }
}

Since it is a JUnit 5 test is uses the official MockitoExtension. It is supposed to test the following class:

@Getter
public class Person {

    private final String name;
    private final String surname;
    private final String pin;

    public Person(String name, String surname, PinProvider pinProvider) {
        this.name = name;
        this.surname = surname;
        this.pin = pinProvider.getPin();
    }
}

Unfortunately, the PinProvider class is final:

public final class PinProvider {

    private static final Random RANDOM = new Random();

    public String getPin() {
        return "pin-" + RANDOM.nextInt(1000000000);
    }
}

This makes the test fail with the following exception:

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class org.igorski.finalexample.PinProvider
Mockito cannot mock/spy because :
 - final class

At this point before Mockito 2, you generally had two choices. Redesign your code, or use Powermock. And the latter is almost never a good thing.

Setup to mock final classes

Mockito 2 brings a solution to this problem. The Mockito team still considers this feature as “incubating” though. It is optional and it if you want to use it you will need to turn it on explicitly. In order to do that create the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with the following content:

mock-maker-inline

After this, the test passes and no exceptions or warnings are thrown. Mission accomplished.

PowerMock problems

Very often projects use both PowerMock and Mockito. But using mock-maker-inline does not play well with PowerMock. PowerMock has its own org.mockito.plugins.MockMaker. Turning on the Mockito mock-maker-inline feature adds a second MockMaker on the classpath, and that’s a problem.

I experienced these problems first hand. I followed PowerMock’s suggestion how to fix but it didn’t work for me. Probably the safest way would be to choose a single approach. Either mock final classes with Mockito or use PowerMock, but not both.

Sharing is caring