For direct, robust verifications of method arguments in Mockito, use an ArgumentCaptor. This simple "spy" captures the method's inputs for evaluation against your expectations.
ArgumentCaptor<String> argCaptor = ArgumentCaptor.forClass(String.class);
verify(mock).thatMethod(argCaptor.capture());
// Now let's see if it 'walks the talk'assertEquals("That's what I'm talking about", argCaptor.getValue());
Here, the method arguments are the "secrets" captured by the ArgumentCaptor, verified with verify(), and validated with assertEquals().
Exercising ArgumentCaptor to its limits
ArgumentCaptor is a valuable tool beyond basic test cases. With its special features, you can broaden your verification landscape and enrich your test semantics.
Checking object properties, not just equality
Go beyond the equals() method and assert specifics:
ArgumentCaptor<MyObject> myObjectCaptor = ArgumentCaptor.forClass(MyObject.class);
verify(mock).mindBenderMethod(myObjectCaptor.capture());
MyObject capturedObj = myObjectCaptor.getValue();
// We're not just concerned about equality, we're also 'attribute-sensitive'assertTrue(capturedObj.attributeOfInterest().equals("This attribute has my interest"));
Arguing with multiple arguments
Multi-argument methods require acute assertiveness. ArgumentCaptor is well-equipped for this:
// Double the arguments, double the captors, double the fun!ArgumentCaptor<ClassA> captorA = ArgumentCaptor.forClass(ClassA.class);
ArgumentCaptor<ClassB> captorB = ArgumentCaptor.forClass(ClassB.class);
verify(mock).multiArgsMethod(captorA.capture(), captorB.capture());
// Let's make sure our agents captured the right stuffassertAll("Everything should check out",
() -> assertEquals(expectedA, captorA.getValue()),
() -> assertTrue(captorB.getValue().bringBalance())
);
Custom matchers: Get logical, not just literal
Use argThat to inject ArgumentMatcher for logical checks:
// We're not just about presence, it's about meaningful presenceverify(mock).deepThinkerMethod(argThat(argument -> argument.isInsightful() && argument.depth() > 10));
ArgumentMatchers: Tips, tricks, and traps
ArgumentMatchers are a pillar of Mockito. Mastering these can improve test fluency and broaden test coverage.
Matcher-specific argument safety
Ensure type safety and explicity using class-specific matchers:
verify(mock).transform(intThat(value -> value > 42), anyString());
// Yes, 42 because we love 'The Hitchhiker's Guide to the Galaxy'
Logical equivalence with argThat
For equivalence based on logic rather than reference:
// When you're not interested in the cover of the book but the story insideverify(mock).refresh(eq(oldValue), argThat(new ObjectEqualityArgumentMatcher<>()));
Consistent matching in multi-arg methods
Always use matchers when invoking a method with multiple ones for consistency:
// To avoid argument confusion, let's use matchers all the way!verify(mock).doTheHokeyPokey(eq(leftFoot), argThat(value -> value instanceof RightHand), any(ClassType.class));
Mastering these will make your tests not only pass but also expressive and meaningful!
Extending ArgumentCaptor usage
ArgumentCaptor has a rich palette of features beyond assertions to provide a versatile testing canvas.
Real methods on captured arguments
Interact with captured instances for state mutation checks or triggering behaviors:
// Looks like the suspect did something interesting. Time to dig deeper!verify(mock).didSomethingWeird(complexObjectCaptor.capture());
ComplexObject suspect = complexObjectCaptor.getValue();
// We're not just watching, we're participating! Let's stir things up a littlesuspect.poke();
assertFalse("Poke should have put suspect to sleep", suspect.isAwake());
Streamline your world with @Captor
Use @Captor annotation for succinct code:
// Because why repeat ourselves?@Captorprivate ArgumentCaptor<FancyObject> captor;
verify(mock).performMagic(captor.capture());
// Abracadabra! Did magic work?assertNotNull("Should not be null after magic", captor.getValue());
Fine-tuning with times and verification modes
Tweak invocations to adapt to your test strategy:
// Time to play detective and count the clues!verify(mock, times(3)).shootInAir(anyString());
verify(mock, atLeastOnce()).shout(anyString());
verify(mock, never()).surrender(any());
Assert expressively with lambda matchers
Use lambdas to make tests telling tales:
// Time to get expressive!verify(mock).handleObjects(argThat(list -> list.stream().anyMatch(item -> item.canSing())));
// Watch out, we got a singer over here!