Argument captors help you catch and check the values passed to methods during tests. This lets you make sure your code sends the right data to other parts.
Argument captors in JUnit
ArgumentCaptor<Type> captor = ArgumentCaptor.forClass(Type.class);
verify(mockObject).methodName(captor.capture());
Type capturedValue = captor.getValue();Replace Type with the class of the argument you want to capture.
Use captor.getValue() to get the single captured argument or captor.getAllValues() for multiple calls.
sendMessage and check it equals "Hello".ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); verify(mock).sendMessage(captor.capture()); String message = captor.getValue(); assertEquals("Hello", message);
addUser and check the user's name.ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class); verify(userService).addUser(captor.capture()); User user = captor.getValue(); assertEquals("Alice", user.getName());
This test checks that when welcomeUser is called with "Bob", the notifyUser method receives the message "Welcome, Bob!".
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import org.mockito.ArgumentCaptor; import org.junit.jupiter.api.Test; class NotificationService { void notifyUser(String message) { // sends notification } } class UserController { private NotificationService notificationService; UserController(NotificationService notificationService) { this.notificationService = notificationService; } void welcomeUser(String username) { String message = "Welcome, " + username + "!"; notificationService.notifyUser(message); } } public class ArgumentCaptorTest { @Test void testWelcomeUserSendsCorrectMessage() { NotificationService mockNotification = mock(NotificationService.class); UserController controller = new UserController(mockNotification); controller.welcomeUser("Bob"); ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); verify(mockNotification).notifyUser(captor.capture()); String capturedMessage = captor.getValue(); assertEquals("Welcome, Bob!", capturedMessage); } }
Argument captors work only with mocks created by Mockito.
Use captor.getAllValues() if the method is called multiple times and you want all arguments.
Always verify the method call before capturing arguments to avoid errors.
Argument captors let you catch and check method arguments in tests.
They help verify that your code sends the right data to other parts.
Use them with Mockito mocks and verify() calls.
Practice
ArgumentCaptor in JUnit tests with Mockito?Solution
Step 1: Understand ArgumentCaptor role
An ArgumentCaptor is used to catch the actual arguments passed to a mock's method during test execution.Step 2: Differentiate from other Mockito features
Unlike mocks or verify count, ArgumentCaptor focuses on capturing and inspecting method arguments.Final Answer:
To capture and inspect the arguments passed to a mocked method -> Option AQuick Check:
ArgumentCaptor captures arguments [OK]
- Confusing ArgumentCaptor with mock creation
- Thinking it counts method calls
- Assuming it stubs return values
ArgumentCaptor for a String argument in JUnit with Mockito?Solution
Step 1: Recall ArgumentCaptor creation syntax
The correct way is to use the static methodforClass()with the class type.Step 2: Check each option for syntax correctness
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); usesArgumentCaptor.forClass(String.class), which is correct. Options B and C incorrectly use constructors, which are not public. ArgumentCaptor<String> captor = ArgumentCaptor.capture(String.class); uses a non-existent methodcapture()for creation.Final Answer:
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); -> Option AQuick Check:
Use forClass() to create captor [OK]
- Trying to instantiate ArgumentCaptor with new
- Using non-existent capture() method
- Omitting the class type in forClass()
List<String> list = mock(List.class);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
list.add("hello");
verify(list).add(captor.capture());
String captured = captor.getValue();Solution
Step 1: Understand the mock and method call
The mock list hasadd("hello")called, so "hello" is passed as argument.Step 2: Verify and capture argument
Theverify(list).add(captor.capture())captures the argument passed toadd(), which is "hello".Final Answer:
"hello" -> Option BQuick Check:
Captured argument matches method call input [OK]
- Assuming captor captures method name
- Expecting null if not stubbed
- Thinking it throws exception without stubbing
ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); verify(mockedList).add(captor.capture()); mockedList.add(5); Integer value = captor.getValue();
Solution
Step 1: Analyze order of method call and verify
Theverify()call must come after the actual method call to check interactions.Step 2: Identify the mistake
Here,verify()is called beforemockedList.add(5), so no interaction is recorded yet.Final Answer:
Theverifycall is before the actual method call -> Option DQuick Check:
Verify after method call [OK]
- Calling verify before method invocation
- Assuming captor resets automatically
- Declaring captor after verify
Solution
Step 1: Understand multiple call verification with ArgumentCaptor
A single ArgumentCaptor can capture all arguments from multiple calls usinggetAllValues().Step 2: Evaluate options for capturing multiple arguments
Use a single ArgumentCaptor and callgetAllValues()after verifying two calls correctly uses one captor and retrieves all captured arguments. Create two separate ArgumentCaptors and verify each call separately is unnecessary and verbose. Use ArgumentCaptor only once; it cannot capture multiple calls is false; captor supports multiple captures. Capture arguments by stubbing the method instead of verify is incorrect because stubbing does not capture arguments.Final Answer:
Use a single ArgumentCaptor and callgetAllValues()after verifying two calls -> Option CQuick Check:
Single captor + getAllValues() captures multiple calls [OK]
- Creating multiple captors unnecessarily
- Thinking captor captures only one call
- Trying to capture arguments via stubbing
Ready to prove it?
Pass the test and this pattern moves unknown
