How does ArgumentCaptor work in Mockito? Can you give an example?

ArgumentCaptor is a Mockito utility that captures the actual argument values passed into a mocked method call, so the test can make assertions on them after the fact.

Key Points: • Create it with ArgumentCaptor.forClass(SomeType.class), then pass captor.capture() as the argument in a verify() call. • After verify(), call captor.getValue() (or getAllValues() for multiple invocations) to retrieve the captured object. • It's most useful when the mocked method doesn't return anything but receives an object whose internal state you need to check. • Unlike ArgumentMatchers like any() or eq(), it doesn't constrain which invocation matches - it records what was actually passed. • Overuse can indicate the code under test could be simplified to return a value instead of passing a mutable object.

Example: For a UserService.save(User) call, you can capture the User object handed to a mocked UserRepository and assert its email field was normalized to lowercase before saving.

Code Example:

@Test
void savesNormalizedUser() {
    UserRepository repo = mock(UserRepository.class);
    UserService service = new UserService(repo);

    service.register("Alice@Example.com");

    ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
    verify(repo).save(captor.capture());

    assertEquals("alice@example.com", captor.getValue().getEmail());
}

Interview Tip: A concise interview answer is:

"ArgumentCaptor lets me capture the actual object a mocked collaborator received so I can assert on its fields after the call, which is essential when the method under test doesn't return a value but mutates or passes on an argument I need to verify."