JUnit 5 Method Parameters - Injecting @Mock and @Captor

Last Updated : 23 Jul, 2025

In JUnit 5, testing with mock objects has been significantly enhanced through the use of Mockito. Two essential annotations for working with Mockito are @Mock and @Captor. The @Mock annotation helps create mock instances of dependencies, while @Captor allows capturing argument values that are passed to methods.

In this article, we will learn how to inject the @Mock and @Captor annotations into JUnit 5 method parameters to simplify test setups and improve readability.

Prerequisites:

  • Basic understanding of the Java and JUnit 5.
  • Familiarity with Mockito for creating the mock objects.
  • Maven for building dependency management.
  • JDK and IntelliJ IDEA installed in your system.

Setting Up the Environment

To use Mockito with JUnit 5, add the following Maven dependencies to the pom.xml file:x

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>

Main Concept: Injecting @Mock and @Captor in JUnit 5 Method Parameters

In JUnit 5, testing with mock objects is made easy with the help of Mockito. The use of @Mock and @Captor allows us to create mocks and capture arguments efficiently, helping us simulate and verify interactions between objects.

What is @Mock?

@Mock is an annotation provided by Mockito for creating mock instances of classes or interfaces. A mock is a simulated version that allows us to mimic the behavior of real objects without invoking their actual implementations. This is particularly useful in unit testing, where we want to isolate the class being tested from its dependencies.

What is @Captor?

@Captor simplifies the process of capturing arguments passed to methods. It wraps the ArgumentCaptor, a utility that helps verify that methods were called with specific arguments.

Implementation to Inject @Mock and @Captor in JUnit 5 Method Parameters

In this example project, we will create a setup that demonstrates how to use @Mock and @Captor in JUnit 5 to test interactions between a UserService and a UserRepository.

Step 1: Create a New Maven Project

Create a new Maven project using IntelliJ IDEA with the following options:

  • Name: mock-captor-example
  • Build System: Maven

Click on the Create button.

Project Metadata

Project Structure

After project creation done successfully, set up the file structure like shown in the below image:

Project Folder Structure

Step 2: Add the JUnit 5 dependencies to pom.xml

Open the pom.xml file and add the necessary dependencies as described earlier.

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.gfg</groupId>
    <artifactId>mock-captor-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- JUnit 5 Dependency -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>

        <!-- Mockito Dependency -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>5.5.0</version>
            <scope>test</scope>
        </dependency>

        <!-- Mockito JUnit 5 Integration -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <version>5.5.0</version>
            <scope>test</scope>
        </dependency>

        <!-- AssertJ for Fluent Assertions -->
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.24.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Step 3: Create the User Class

Create the User class and this is a simple class that represents the User.

Java
package com.gfg;

// Represents a User with name and email attributes
public class User {
    private String name; // User's name
    private String email; // User's email

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // Getter for name
    public String getName() {
        return name;
    }

    // Getter for email
    public String getEmail() {
        return email;
    }

    // Setter for name
    public void setName(String name) {
        this.name = name;
    }

    // Setter for email
    public void setEmail(String email) {
        this.email = email;
    }
}

Step 4: Create the UserRepository Interface

Create the UserRepository Interface and this interface simulates the database operations.

Java
package com.gfg;

// Interface representing user repository operations
public interface UserRepository {
    void update(int id, User user); // Method to update a user
}

Step 5: Create the UserService Class

Create the UserService class and this class contains the bussiness logic for updating a user.

Java
package com.gfg;

// UserService class to manage user-related operations
public class UserService {
    private final UserRepository userRepository; // Dependency on UserRepository

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository; // Constructor injection of UserRepository
    }

    // Method to update a user's information
    public void updateUser(int id, User user) {
        userRepository.update(id, user); // Calls the update method on the repository
    }
}

Step 6: Main Class

The MainApplication class serves as the entry point for demonstration.

Java
package com.gfg;

// Main application to demonstrate user updating
public class MainApplication {
    public static void main(String[] args) {
        // Create a mock UserRepository for demonstration
        UserRepository userRepository = new UserRepository() {
            @Override
            public void update(int id, User user) {
                // Print statements to simulate database update operation
                System.out.println("Updating user with ID: " + id);
                System.out.println("Name: " + user.getName());
                System.out.println("Email: " + user.getEmail());
            }
        };

        // Create the UserService instance with the mock repository
        UserService userService = new UserService(userRepository);

        // Create a new user
        User user = new User("John Doe", "john.doe@example.com");

        // Update user information using the service
        userService.updateUser(1, user);
    }
}

Step 7: Create the UserServiceTest class

Create the UserServiceTest class and this is the test class where we use @Mock and @Captor.

Java
import com.gfg.User;
import com.gfg.UserRepository;
import com.gfg.UserService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.eq;

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @InjectMocks
    private UserService userService;

    @Mock
    private UserRepository userRepository;

    @Captor
    private ArgumentCaptor<User> userCaptor;

    @Test
    void testUpdateUser() {
        // Create a User object
        User user = new User("Jane Doe", "jane.doe@example.com");

        // Call the updateUser method
        userService.updateUser(1, user);

        // Verify that userRepository.update was called with the correct User
        verify(userRepository).update(eq(1), userCaptor.capture());

        // Get the captured User
        User capturedUser = userCaptor.getValue();

        // Perform assertions on the captured User object
        assertThat(capturedUser.getName()).isEqualTo("Jane Doe");
        assertThat(capturedUser.getEmail()).isEqualTo("jane.doe@example.com");
    }
}

Explanation:

  • @ExtendWith(MockitoExtension.class): Enables Mockito’s JUnit 5 integration, allowing the use of annotations like @Mock, @Captor, and @InjectMocks.
  • @InjectMocks: Creates an instance of UserService and injects the mock UserRepository into it.
  • @Mock: Creates a mock object of UserRepository, which is used in the UserService class.
  • @Captor: Initializes an ArgumentCaptor to capture arguments passed to the update method of the UserRepository.
  • The testUpdateUser() method:
    • Creates a User object with test data.
    • Calls the updateUser method to simulate updating a user.
    • Verifies that the update method of the userRepository was called with the expected user.
    • Uses assertions to check that the captured User object has the correct name and email.

Step 8: Run the Application

After completing the project, run the application, and it will start at port 8080.

Output

Step 9: Running the Tests

We will now run the UserServiceTest using the below command:

mvn test

Output:

Test Output

This example project demonstrates how to use the @Mock and @Captor effectively in the Maven project, ensuring that we can test the interaction between classes in the project.

Comment
Article Tags:

Explore