Mockito Mocking Constructors

Introduction

In this chapter, we will learn about mocking constructors using Mockito. Constructor mocking allows you to control the behavior of objects that are created within the class under test. This can be particularly useful when the class being instantiated performs complex initialization or interacts with external systems.

What is Mocking Constructors?

Mocking constructors involves intercepting the creation of an object using its constructor and replacing it with a mock. This is useful for isolating tests from the actual implementations of the classes being instantiated.

Setting Up Mockito to Mock Constructors

To mock constructors with Mockito, you need to use the mockito-inline library, which provides the necessary functionality. Ensure that you have the following dependencies in your pom.xml if you are using Maven:

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>5.2.0</version>
    <scope>test</scope>
</dependency>
<!-- JUnit 5 dependency -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>

Example: EmailService Class and NotificationService Class

In this example, we have a NotificationService class that uses an EmailService object. We will mock the constructor of EmailService to test the NotificationService class.

Class Under Test: NotificationService

public class NotificationService {
    public boolean sendNotification(String email, String message) {
        EmailService emailService = new EmailService(email);
        return emailService.sendEmail(message);
    }
}

Class to be Mocked: EmailService

public class EmailService {
    private String email;

    public EmailService(String email) {
        this.email = email;
    }

    public boolean sendEmail(String message) {
        // Logic to send email
        return true;
    }
}

Test Class: NotificationServiceTest

import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import static org.junit.jupiter.api.Assertions.*;

public class NotificationServiceTest {

    @Test
    void testSendNotification_MockConstructor() {
        try (MockedConstruction<EmailService> mocked = mockConstruction(EmailService.class,
                (mock, context) -> {
                    // Mock the sendEmail method
                    when(mock.sendEmail(anyString())).thenReturn(false);
                })) {

            // Create an instance of NotificationService
            NotificationService notificationService = new NotificationService();

            // Call the method under test
            boolean result = notificationService.sendNotification("test@example.com", "Hello!");

            // Assert the result
            assertFalse(result);

            // Verify that the constructor was called
            assertEquals(1, mocked.constructed().size());
            verify(mocked.constructed().get(0)).sendEmail("Hello!");
        }
    }
}

Explanation

  1. Mocking the Constructor:
    try (MockedConstruction<EmailService> mocked = mockConstruction(EmailService.class,
            (mock, context) -> {
                // Mock the sendEmail method
                when(mock.sendEmail(anyString())).thenReturn(false);
            })) {
    

    This line creates a mock construction for the EmailService class. The mockConstruction method allows us to intercept the creation of EmailService objects and replace them with mocks.

  2. Creating an Instance of NotificationService:
    NotificationService notificationService = new NotificationService();
    

    This line creates an instance of the NotificationService class.

  3. Calling the Method Under Test:
    boolean result = notificationService.sendNotification("test@example.com", "Hello!");
    

    This line calls the sendNotification method on the NotificationService instance with the specified arguments.

  4. Asserting the Result:
    assertFalse(result);
    

    This line asserts that the returned value matches the expected result (false).

  5. Verifying the Constructor and Method Calls:
    assertEquals(1, mocked.constructed().size());
    verify(mocked.constructed().get(0)).sendEmail("Hello!");
    

    These lines verify that the constructor was called once and that the sendEmail method was called with the specified argument.

Output

Mockito Mocking Constructors

Example: DatabaseService Class and UserService Class

Let’s consider another practical example where we have a UserService class that uses a DatabaseService object. We will mock the constructor of DatabaseService to test the UserService class.

Class Under Test: UserService

public class UserService {
    public boolean createUser(String username, String password) {
        DatabaseService databaseService = new DatabaseService();
        return databaseService.saveUser(username, password);
    }
}

Class to be Mocked: DatabaseService

public class DatabaseService {
    public boolean saveUser(String username, String password) {
        // Logic to save user to the database
        return true;
    }
}

Test Class: UserServiceTest

import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import static org.junit.jupiter.api.Assertions.*;

public class UserServiceTest {

    @Test
    void testCreateUser_MockConstructor() {
        try (MockedConstruction<DatabaseService> mocked = mockConstruction(DatabaseService.class,
                (mock, context) -> {
                    // Mock the saveUser method
                    when(mock.saveUser(anyString(), anyString())).thenReturn(false);
                })) {

            // Create an instance of UserService
            UserService userService = new UserService();

            // Call the method under test
            boolean result = userService.createUser("testuser", "password");

            // Assert the result
            assertFalse(result);

            // Verify that the constructor was called
            assertEquals(1, mocked.constructed().size());
            verify(mocked.constructed().get(0)).saveUser("testuser", "password");
        }
    }
}

Explanation

  1. Mocking the Constructor:
    try (MockedConstruction<DatabaseService> mocked = mockConstruction(DatabaseService.class,
            (mock, context) -> {
                // Mock the saveUser method
                when(mock.saveUser(anyString(), anyString())).thenReturn(false);
            })) {
    

    This line creates a mock construction for the DatabaseService class. The mockConstruction method allows us to intercept the creation of DatabaseService objects and replace them with mocks.

  2. Creating an Instance of UserService:
    UserService userService = new UserService();
    

    This line creates an instance of the UserService class.

  3. Calling the Method Under Test:
    boolean result = userService.createUser("testuser", "password");
    

    This line calls the createUser method on the UserService instance with the specified arguments.

  4. Asserting the Result:
    assertFalse(result);
    

    This line asserts that the returned value matches the expected result (false).

  5. Verifying the Constructor and Method Calls:
    assertEquals(1, mocked.constructed().size());
    verify(mocked.constructed().get(0)).saveUser("testuser", "password");
    

    These lines verify that the constructor was called once and that the saveUser method was called with the specified arguments.

Conclusion

Mocking constructors using Mockito allows you to isolate your tests from the actual implementations of the classes being instantiated. By using the mockito-inline library, you can mock constructors and verify their interactions, making your tests more robust and maintainable. Understanding and utilizing constructor mocking will help you write more effective and isolated unit tests. In this chapter, we covered two examples: mocking the constructor of an EmailService class in a NotificationService test and mocking the constructor of a DatabaseService class in a UserService test. These examples demonstrate how to use Mockito to mock constructors and verify their behavior in different scenarios.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top