Mockito @Captor Annotation Tutorial

1. Overview

Mockito, a popular testing framework in the Java ecosystem, offers a variety of annotations to streamline the process of mock creation and interaction. Among these annotations, @Captor stands out for its unique utility. 

@Captor is an annotation used in Mockito to create an ArgumentCaptor instance. ArgumentCaptor captures the argument passed to a method call, thus allowing you to use it in further assertions in your tests. In this tutorial, we'll explore the functionality of the @Captor annotation in detail.

2. Development Steps

1. Initialize a Maven project.

2. Integrate the required dependencies (JUnit 5 and Mockito).

3. Create a service class with a method that takes an object as an argument.

4. Frame a test class for the service.

5. Use @Mock for mock creation and @Captor to capture the method argument.

6. Implement and run the test cases.

7. Analyze the test outcomes.

3. Dependencies (Mockito and JUnit 5)

<!-- JUnit 5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>5.6.0</version>
    <scope>test</scope>
</dependency>

4. Code Program

// Step 3: Design the Service and DTO classes
class UserData {
    private String name;
    UserData(String name) {
        this.name = name;
    }
    String getName() {
        return name;
    }
}

interface UserService {
    void saveUser(UserData user);
}

// Step 4 and 5: Frame a test class for 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.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @Mock
    private UserService userServiceMock;
    
    @Captor
    private ArgumentCaptor<UserData> userDataArgumentCaptor;
    
    @Test
    public void saveUserTest() {
        UserData userData = new UserData("John Doe");
        userServiceMock.saveUser(userData);
        // Capture the argument passed to the saveUser method
        verify(userServiceMock).saveUser(userDataArgumentCaptor.capture());
        UserData capturedUser = userDataArgumentCaptor.getValue();
        assertEquals("John Doe", capturedUser.getName());
    }
}

Output:

The saveUserTest will pass successfully, verifying that the correct user data was passed to the saveUser method.

Code Explanation:

1. After setting up Mockito and JUnit 5 dependencies, we introduced two classes: UserData which represents a user data DTO, and UserService which is an interface containing a method to save user data.

2. In our test class, we utilized the @Mock annotation to create a mock for the UserService.

3. The @Captor annotation is used to declare an ArgumentCaptor for the UserData type. This captor will help us capture the arguments passed to the mocked method. Instead of manually creating an ArgumentCaptor, Mockito provides the @Captor annotation which automatically initializes the ArgumentCaptor instance for you.

4. In the saveUserTest method, after invoking the saveUser method on the mock, we used the verify method to ensure that our method was called. Simultaneously, we captured the argument passed to it using the ArgumentCaptor.

5. Finally, we retrieved the captured argument using getValue() and asserted that the user data is as expected.

5. Conclusion

The @Captor annotation in Mockito provides a straightforward way to capture and verify the arguments passed to mocked methods. It's especially useful when we're less concerned about the output of a method and more interested in ensuring that the method was invoked with the correct parameters. By understanding the utility of this annotation, developers can write more precise and thorough unit tests.

Related Mockito Annotations

Comments