Contents

How to use the Mockito's inline mock maker

Written by: David Vlijmincx

Introduction

Below you will find five ways of using Mockito that will help you write better tests. We are going to find out how to mock a constructor, mock static methods, have stricter mocking rules, mock final methods and classes, and how to use verify with argument captors.

Maven Dependency

For the examples, I used version 5.12.0 of Mockito.

1
2
3
4
5
6
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.12.0</version>
    <scope>test</scope>
</dependency>

Using Mockito 4?

If you are using Mockito 4 you need to do some extra work to enable the mock-maker-inline. There are a few ways of doing this. I listed the options below.

Option 1: Mock maker inline dependency

Add this dependency in your pom.

1
2
3
4
5
6
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>4.2.0</version>
    <scope>test</scope>
</dependency>

Option 2: Adding a file to enable the Mock maker inline

Create a resources directory in your test directory if you do not have one. In resources create the directory mockito-extensions and in that directory the file org.mockito.plugins.MockMaker. The complete path should look like this: src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker.

In the file, add the following line mock-maker-inline. Now the mock maker inline is available to use.

Option 3: Upgrade to Mockito 5

If you want to know more about Mockito 5 please see this post about upgrading to Mockito 5

Mocking constructors

With the mockConstruction you can mock calls made to the constructor. For example, we mock the constructor for the class Dog when your code calls the constructor, it returns a mock object. Keep this code in a try with resources to limit the scope, so you only mock the constructor in that test method.

If the method that you are testing calls the constructor of a class, that you want to mock, you don't have direct access to change its mocking behavior. To get a reference of the created mock, you can call the constructed() method on the MockedConstruction instance. It returns a list of all the created mock objects. The example below uses it to see how often the constructor is called.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Dog {
    public Dog() {}
    public String makeSound() {return "Woof";}
}

    @Test
    void mockingConstructor() {

        try (MockedConstruction<Dog> mock = mockConstruction(Dog.class)) {
            Dog dog = new Dog();
            when(dog.makeSound()).thenReturn("Bark");

            assertThat(dog.makeSound()).isEqualTo("Bark");

            List<Dog> constructed = mock.constructed();
            assertThat(constructed).hasSize(1);
        }
        assertThat(new Dog().makeSound()).isEqualTo("Woof");

    }

Mocking Static methods

With the inline mock maker, it's possible to mock static methods. The example shows how to mock the static method Instant.now(). Every call made to it will return a mock of Instant. Use a try with resources to limit the scope of the static method mocking to its test method.

I also included a version that uses LocalDateTime, because I often want to mock one of these classes without changing production code or using PowerMock.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
void mockingStaticMethods() {

    try (MockedStatic<Instant> mocked = mockStatic(Instant.class)) {
        var mockInstant = mock(Instant.class);
        when(mockInstant.getEpochSecond()).thenReturn(0l);
        mocked.when(Instant::now).thenReturn(mockInstant);

        var result = Instant.now();

        assertThat(result.getEpochSecond()).isEqualTo(0);
    }

    try (MockedStatic<LocalDateTime> mocked = mockStatic(LocalDateTime.class)) {
        var mockLocalDateTime = mock(LocalDateTime.class);
        when(mockLocalDateTime.getMinute()).thenReturn(30);
        mocked.when(LocalDateTime::now).thenReturn(mockLocalDateTime);

        var result = LocalDateTime.now();

        assertThat(result.getMinute()).isEqualTo(30);
    }

}

Use strict mocking

Mockito is a loose mocking framework by default which means that you are allowed to create Mocks that have no interaction. Making Mockito stricter forces you to be explicit about what you want to test, or the test will fail. Setting the Strictness to STRICT_STUBS will result in higher quality and cleaner tests.

Below is an example of how we can achieve this. The code is run before and after each test so that mockito can tell which test is invalid.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class YourTestClass {

    MockitoSession mockito;

    @BeforeEach
    void setup() {
        mockito = Mockito.mockitoSession()
                .strictness(Strictness.STRICT_STUBS)
                .startMocking();
    }

    @AfterEach
    void tearDown() {
        mockito.finishMocking();
    }

}

Mocking final methods and classes

With the inline mock maker, you can mock final classes and methods. You can do this using mock(SomeClazz.class) like you would with every other object you want to mock. In the example, we see it is the same as with non-final classes and methods.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
final class Cat {
    final String makeSound() {return "Meow";}
}

@Test
void mockingFinalClasses() {
    Cat cat = mock(Cat.class);
    when(cat.makeSound()).thenReturn("purr");
    assertThat(cat.makeSound()).isEqualTo("purr");
}

Combine verify with argument matchers

Normally you would use an instance of an ArgumentCaptor to verify the input of a mocked method. But that results in multiple lines of code that you need to maintain. While it could be worth it if you do a lot of assertions. There is an easier way for less complex cases. With argThat we create a custom matcher that is validated against the input of each method invocation.

1
2
3
4
5
6
7
@Test
void simpleArgumentMatchers() {
    List<String> list = (List<String>) mock(List.class);
    list.add("one");
    list.add("two");
    verify(list, times(2)).add(argThat(a -> a.contains("o")));
}

If we mock a method that has multiple arguments, we need to add an extra argThat like this:

1
2
3
4
5
6
7
@Test
void simpleArgumentMatchersMultipleArguments() {
    Map<String, Integer> map = (Map<String, Integer>) mock(Map.class);
    map.put("one", 1);
    map.put("two", 2);
    verify(map, times(2)).put(argThat(a -> a.contains("o")), argThat(a -> a < 3));
}

Conclusion

I hope these few methods will help you write better tests, it helped me a lot to write higher-quality tests.

If you are curious and want to know more about what you can do with Mockito, please check out their documentation. It lists all the Mockito features and how to use them.

Further reading

More about testing in Java: