Contents

Mock constructor calls with Mockito

Introduction

Enabling Mockito's mock maker inline allows you to mock more with Mockito than you could by default. This post explains how to enable and use it to mock constructors.

Maven Dependency

For the examples, I used version 4.2.0 of Mockito.

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

We also need the Mock maker inline to mock constructors. We can add a dependency or create a file inside the test resources to enable the new Mock maker.

Option 1: Mock maker inline dependency

Add this dependency in your pom.xml to enable Mockito's Mock maker inline. We need the Mock maker inline to mock constructors.

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

If you don't want to or can't add a dependency, you can also use a file to enable the mock maker inline. Create a resources directory in your test directory if you do not have one already. Inside the resources create the directory mockito-extensions and in that directory the file org.mockito.plugins.MockMaker. The complete path with file should look like this: src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker.

in the file org.mockito.plugins.MockMaker paste this text mock-maker-inline, now the mock maker is available during tests.

Mocking constructors

With the mockConstruction you can mock calls made to the constructor. For example, we mock the constructor for the class Dog. The test code is inside a try with resources to limit the scope. When your code calls the constructor inside the try statement, it returns a mock object. Outside the try-with-resources statement the constructor won't be mocked by Mockito.

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

@Test
void mockingConstructor() {

    // Scope of constructor mocking
    try (MockedConstruction<Dog> mock = mockConstruction(Dog.class)) {
        // creating a mock instance
        Dog dog = new Dog();
        when(dog.makeSound()).thenReturn("Bark");

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

        // Get a list of all created mocks
        List<Dog> constructed = mock.constructed();
        assertThat(constructed).hasSize(1);
    }
    
    // Normal Dog instance that is not mocked
    assertThat(new Dog().makeSound()).isEqualTo("Woof");

}

Mock constructor inside another class

Sometimes we want to mock an object that is created inside another class. In the following example we have two classes called House and Dog. Inside the class House an instance of Dog is created. To mock the Dog we could add parameter for Dog to the constructor of the House class, or we could mock the constructor of Dog and return a mock object.

In the example below we mock the dogs constructor inside a try statement. When a new House instance is created, a mock object of dog is also created.
We use mock.constructed().get(0) to get the firstly created mocked instance of Dog. This instance can be used to verify calls, stubbing, and more.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
void testObjectCreation(){
    try (MockedConstruction<Dog> mock = mockConstruction(Dog.class)) {
        House house = new House();
        
        // Get the first mock
        Dog mockDog = mock.constructed().get(0);

        verify(mockDog).setName("Rex");
    }
}

class House{

    public House() {
     Dog pet = new Dog();
     pet.setName("Rex");
     System.out.println(pet.makeSound());
    }

}

Change default mock behavior

Methods we don't stub of a mock return null by default. We can take the examples one step further and let the mock behave like a real Dog instance. The MockedConstruction is again inside a try with resources, but this time we pass it an extra parameter. When we pass withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS) to the MockedConstruction we tell it to create a mock that will behave like a real Dog instance for methods that we didn't stub.

1
2
3
4
5
6
7
@Test
void defaultMethods(){
    try (MockedConstruction<Dog> mock = mockConstruction(Dog.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS))) {
        Dog dog = new Dog();
        System.out.println(dog.makeSound());
    }
}

By default, this would print null to the console, but now it prints Woof.

Conclusion

In this post, we enabled the inline mock maker to mock constructors. We also saw two examples of how to create a MockedConstruction object and change its behavior.

If you are curious and want to know more about what you can do with Mockito, please check out their documentation https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html. It lists all the Mockito features and how to use them.

Further reading

More about testing in Java:

If you want to read more about Java when I write about it – you can follow me on Twitter.