Java > Testing in Java > Unit Testing > Mocking with Mockito
Mockito: Argument Captor Example
This snippet demonstrates how to use Mockito's `ArgumentCaptor` to capture arguments passed to mocked methods during unit testing in Java. This is helpful when you need to inspect the arguments passed to a mocked method to ensure they are correct.
Defining the Service Interface
This interface defines a method for sending messages.
public interface MessageService {
void sendMessage(String recipient, String message);
}
Defining the Message Sender Class
This class uses a MessageService to send notifications. The `sendNotification` method formats a message and then sends it using the injected `MessageService`.
public class MessageSender {
private final MessageService messageService;
public MessageSender(MessageService messageService) {
this.messageService = messageService;
}
public void sendNotification(String user, String content) {
String fullMessage = "Dear " + user + ",\n" + content;
messageService.sendMessage(user, fullMessage);
}
}
Unit Test with ArgumentCaptor
This test demonstrates how to use `ArgumentCaptor`. * First, we create a mock `MessageService`. * Then, we create a `MessageSender` and inject the mock. * We create an `ArgumentCaptor` for the `String` type, which will capture the message argument passed to the `sendMessage` method. * We call the `sendNotification` method on the `MessageSender`. * We use `verify(messageService).sendMessage(eq(user), messageCaptor.capture())` to verify that the `sendMessage` method was called with the correct recipient and to capture the message argument. `eq(user)` ensures that the `recipient` argument is equal to the `user` variable. `messageCaptor.capture()` captures the message argument. The `eq()` matcher must be used for all arguments except the one you are capturing. This is a Mockito requirement. * Finally, we retrieve the captured message using `messageCaptor.getValue()` and assert that it is equal to the expected message.
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
class MessageSenderTest {
@Test
void sendNotification_validInput_messageSentWithCorrectContent() {
// Arrange
MessageService messageService = Mockito.mock(MessageService.class);
MessageSender messageSender = new MessageSender(messageService);
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
String user = "Alice";
String content = "Your account has been updated.";
// Act
messageSender.sendNotification(user, content);
// Assert
verify(messageService).sendMessage(eq(user), messageCaptor.capture());
String capturedMessage = messageCaptor.getValue();
String expectedMessage = "Dear Alice,\nYour account has been updated.";
assertEquals(expectedMessage, capturedMessage);
}
}
Concepts Behind the Snippet
The key concept here is capturing the arguments passed to a mocked method for inspection. This is useful when you need to verify that the method was called with specific arguments, especially when those arguments are complex objects or dynamically generated.
Real-Life Use Case
Imagine you are testing an order processing system. You might mock a payment gateway service. Using `ArgumentCaptor`, you can capture the payment details (e.g., credit card number, amount) sent to the payment gateway and verify that the correct information is being passed. This ensures that the order is being processed correctly and that the payment gateway is receiving the right data.
Best Practices
Interview Tip
Be prepared to explain how `ArgumentCaptor` works and when you would use it. Understand the difference between verifying method calls and capturing arguments. Also, be prepared to discuss scenarios where `ArgumentCaptor` is a more appropriate solution than other Mockito features.
When to Use Argument Captor
Argument Captor is most valuable in situations where:
Alternatives
Pros
Cons
FAQ
-
Why do I need to use `eq()` matcher with ArgumentCaptor?
Mockito requires you to use matchers (like `eq()`, `any()`, etc.) for all arguments in the `verify()` method when you're using an `ArgumentCaptor`. If you try to mix a raw value with a matcher, Mockito won't know how to interpret the arguments. `eq(value)` creates a matcher that matches only if the argument is equal to `value`. -
Can I use ArgumentCaptor with multiple arguments?
Yes, you can use multiple `ArgumentCaptor` instances in a single test to capture multiple arguments passed to the same method. -
When is it better to use ArgumentCaptor over just asserting a direct result?
Use `ArgumentCaptor` when you need to inspect the exact values being passed to a dependency, especially when: * The dependency has side effects, and you need to verify the correct data was passed. * The dependency returns no value or its return value is not relevant to the test. * The arguments being passed are complex objects and you need to verify their internal state.