Introduction
In this chapter, we will learn about the @Captor
annotation in Mockito. This annotation is used to create an ArgumentCaptor, which is a powerful feature for capturing arguments passed to mock methods. Captors allow you to verify and inspect the arguments that were passed to the methods of your mocks.
Key Points about the @Captor Annotation
- Captures Arguments: The
@Captor
annotation creates an ArgumentCaptor to capture arguments passed to mock methods. - Verification and Inspection: Allows verification and inspection of method arguments to ensure they match expected values.
- Simplifies Argument Capture: Reduces boilerplate code needed for capturing and asserting arguments.
- Initialization: Requires initialization using
MockitoAnnotations.openMocks(this)
.
Setting Up Mockito for @Captor Annotation
Ensure that you have the necessary dependencies in your pom.xml
if you are using Maven:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</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>
</dependencies>
Example: Using @Captor Annotation
Description
In this example, we will create an OrderService
class that depends on a PaymentService
class. The OrderService
class will use the PaymentService
class to process payments for orders. We will create unit tests for the OrderService
class using Mockito’s @Captor
annotation to capture and verify the arguments passed to the PaymentService
.
Class Under Test: OrderService
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void placeOrder(String productId, int quantity) {
paymentService.processPayment(productId, quantity);
}
}
Supporting Class: PaymentService
public class PaymentService {
public void processPayment(String productId, int quantity) {
// Logic to process payment
}
}
Test Class: OrderServiceTest
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
public class OrderServiceTest {
@Mock
private PaymentService paymentService;
@InjectMocks
private OrderService orderService;
@Captor
private ArgumentCaptor<String> productIdCaptor;
@Captor
private ArgumentCaptor<Integer> quantityCaptor;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void testPlaceOrder_CapturesArguments() {
// Act
orderService.placeOrder("product123", 2);
// Assert
verify(paymentService).processPayment(productIdCaptor.capture(), quantityCaptor.capture());
assertEquals("product123", productIdCaptor.getValue());
assertEquals(2, quantityCaptor.getValue());
}
}
Explanation
- Mock Annotation:
@Mock private PaymentService paymentService;
The
@Mock
annotation creates a mock object for thePaymentService
class. - InjectMocks Annotation:
@InjectMocks private OrderService orderService;
The
@InjectMocks
annotation creates an instance of theOrderService
class and injects thePaymentService
mock into it. - Captor Annotation:
@Captor private ArgumentCaptor<String> productIdCaptor; @Captor private ArgumentCaptor<Integer> quantityCaptor;
The
@Captor
annotation creates ArgumentCaptors for capturing the arguments passed to theprocessPayment
method of thePaymentService
mock. - Initializing Mocks:
@BeforeEach void setUp() { MockitoAnnotations.openMocks(this); }
The
MockitoAnnotations.openMocks(this)
method initializes the mock objects and ArgumentCaptors. This is typically done in a@BeforeEach
method to ensure mocks and captors are set up before each test. - Test Method:
@Test void testPlaceOrder_CapturesArguments() { // Act orderService.placeOrder("product123", 2); // Assert verify(paymentService).processPayment(productIdCaptor.capture(), quantityCaptor.capture()); assertEquals("product123", productIdCaptor.getValue()); assertEquals(2, quantityCaptor.getValue()); }
This test method captures the arguments passed to the
processPayment
method (Act), verifies that the method was called, and asserts that the captured arguments match the expected values (Assert).
Conclusion
The @Captor
annotation in Mockito is used for capturing and verifying arguments passed to mock methods. It simplifies the process of capturing arguments, reducing boilerplate code and making tests cleaner and more maintainable. This approach helps ensure that the arguments passed to methods in your mocks are correct, improving the accuracy and reliability of your tests.