Explain Codes LogoExplain Codes Logo

Mockito. Verify method arguments

java
argument-capturing
mockito-verification
test-assertions
Anton ShumikhinbyAnton Shumikhin·Oct 18, 2024
TLDR

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 stuff assertAll("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 presence verify(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 inside verify(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 little suspect.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? @Captor private 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!