BackendBench
Coffee

Unravel › Java concepts › Testing

Testing

Advanced Mockito (matchers, captors, static mocks)

Mockito does more than when(...).thenReturn(...).

Learn these first

At a glance

Mental model

A stunt double with a notebook.

What happens, in order
  1. 1Verification: verify(mailer, times(2)).send(any()), never(), atLeastOnce(), inOrder(a, b), and verifyNoMoreInteractions(mailer) to prove nothing else happened
  2. 2Capturing: ArgumentCaptor<Email> captor = ArgumentCaptor.forClass(Email.class); verify(mailer).send(captor.capture()); assertEquals("Hi", captor.getValue().subject()); checks the object that was actually sent
  3. 3Stubbing void methods and exceptions: doThrow(new IOException()).when(client).upload(any()), doAnswer(inv -> ...)BDD style: given(repo.find(1L)).willReturn(order).
  4. 4Matchers: any(), eq(), argThat(x -> x.total() > 0); when one argument uses a matcher, all of them must (eq("a") for the raw ones)
Remember
Watch out
Mixing matchers and raw values in one callVerifying every internal callStatic mocking as the default toolStubbing the class under test (a spy) instead of its collaborators
Example (highlighted lines explain it)
@ExtendWith(MockitoExtension.class)class NotifierTest {    @Mock Mailer mailer;    @InjectMocks Notifier notifier;    @Test    void sendsOneEmailWithOrderNumber() {        notifier.orderShipped(new Order("o-7", "ana@acme.com"));        ArgumentCaptor<Email> captor = ArgumentCaptor.forClass(Email.class);        verify(mailer, times(1)).send(captor.capture());        assertTrue(captor.getValue().body().contains("o-7"));        verifyNoMoreInteractions(mailer);    }}
  1. line 1 uses MockitoExtension, the core of Advanced Mockito (matchers, captors, static mocks)
  2. line 10 uses forClass, the core of Advanced Mockito (matchers, captors, static mocks)
  3. line 13 uses verifyNoMoreInteractions, the core of Advanced Mockito (matchers, captors, static mocks)
Read the full explanation (about 1 min)

Mockito does more than when(...).thenReturn(...). You can verify call order and counts, capture the arguments that were passed, stub void methods and exceptions, and in rare cases replace static methods or constructors.

A mental model

A stunt double with a notebook. Besides standing in for the real actor, the double writes down exactly what was said to them, in which order, and how many times.

How it works

Verification: verify(mailer, times(2)).send(any()), never(), atLeastOnce(), inOrder(a, b), and verifyNoMoreInteractions(mailer) to prove nothing else happened.

Capturing: ArgumentCaptor<Email> captor = ArgumentCaptor.forClass(Email.class); verify(mailer).send(captor.capture()); assertEquals("Hi", captor.getValue().subject()); checks the object that was actually sent.

Stubbing void methods and exceptions: doThrow(new IOException()).when(client).upload(any()), doAnswer(inv -> ...). BDD style: given(repo.find(1L)).willReturn(order).

Matchers: any(), eq(), argThat(x -> x.total() > 0); when one argument uses a matcher, all of them must (eq("a") for the raw ones).

Going deeper

mockStatic replaces a static method for the current thread inside a try-with-resources block. It is a last resort for legacy code (LocalDate.now(), utility classes); inject a Clock or a wrapper instead to avoid it.

Strict stubs (default with MockitoExtension) fail tests that set up stubbing never used, which finds dead set-up. Use lenient() only on purpose.

Over-verification couples tests to the implementation: if every internal call is verified, refactoring breaks tests that did not need to. Verify outcomes and important interactions (a message sent, a payment charged), not every method call.

Under the hood

Mockito generates a subclass or inline instrumentation (ByteBuddy) of the mocked type. Every call on the mock is recorded in an invocation container; when(...) registers a stubbing against the last invocation; verify matches recorded invocations against your expectation and the matchers on the argument stack.

Common mistakes

  • Mixing matchers and raw values in one call.
  • Verifying every internal call.
  • Static mocking as the default tool.
  • Stubbing the class under test (a spy) instead of its collaborators.

How Unravel recognises it

When you paste code, Unravel looks for these signs of advanced mockito (matchers, captors, static mocks). Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Advanced Mockito (matchers, captors, static mocks)?

Mockito does more than when(...).thenReturn(...). You can verify call order and counts, capture the arguments that were passed, stub void methods and exceptions, and in rare cases replace static methods or constructors.

What are the most common mistakes with Advanced Mockito (matchers, captors, static mocks)?

Mixing matchers and raw values in one call. Verifying every internal call. Static mocking as the default tool. Stubbing the class under test (a spy) instead of its collaborators.

How can I see Advanced Mockito (matchers, captors, static mocks) in real code?

Paste your own Java into Unravel and it will point out where advanced mockito (matchers, captors, static mocks) appears, explain how it works at the detail level you choose, and draw the flow of the code around it.