Verifying Interactions
Verifying Interactions
In the previous lesson you learned how to configure Mockito stubs so collaborators return canned values. Stubbing answers the question "what does the collaborator return?" — but a large class of bugs is not about return values at all. They are about whether your code called the right method, with the right arguments, the right number of times. That is what interaction verification is for.
Why Verify Interactions?
Consider an OrderService that is supposed to send a confirmation email after a successful order. The email service returns void — there is nothing to stub. Your only way to assert the behaviour is to verify that emailService.sendConfirmation(order) was actually invoked. Without that assertion, the test passes even if you delete the call entirely.
Basic verify()
The simplest form asserts that a method was called exactly once:
verify(mock).method(args) — no extra call to times() — defaults to times(1). If the method was never called, or called more than once, the test fails with a clear message showing the actual invocations.
Controlling Invocation Count
Mockito ships several VerificationMode factories:
verify(billing, never()).charge(...) is the clearest way to document and enforce that constraint.
verifyNoMoreInteractions() and verifyNoInteractions()
After all your targeted verify() calls, you can assert that nothing unexpected happened:
Argument Matchers
Sometimes you need to verify a call without caring about every argument. Mockito provides a rich library of argument matchers in org.mockito.ArgumentMatchers:
Matchers can be mixed — but there is one rule: if you use a matcher for any argument, you must use matchers for all arguments. You cannot mix raw values and matchers in the same call.
ArgumentCaptor — Capturing for Deep Inspection
Argument matchers are binary — a call either matches or it does not. When you need to inspect the captured argument in detail (assert on multiple fields, log it for debugging, reuse it), use ArgumentCaptor:
With the annotation-based style (requires @ExtendWith(MockitoExtension.class)) you can declare the captor as a field:
When the same collaborator method is called multiple times, captor.getAllValues() returns the full list in invocation order:
Verification Order
By default, verify() does not care about call order. When the sequence matters — for example, you must flush a cache before writing to the database — use InOrder:
Professional Trade-offs
- Interaction tests are white-box. They couple the test to the implementation, not the contract. A refactoring that is externally equivalent but restructures internal calls will break interaction tests. Use them deliberately.
- Argument captors for complex assertions are fine, but if you find yourself capturing and asserting on five fields, consider whether the collaborator should receive a dedicated value object that you can construct and compare directly with
eq(). - Prefer one verification concern per test. Mixing state assertions with multiple interaction verifications obscures what the test is actually about.
Summary
verify() is the tool for asserting that your code called a collaborator as expected. Argument matchers let you write flexible verifications without coupling to exact values. ArgumentCaptor lets you pull the actual argument out of the mock so you can run detailed assertions on it. InOrder enforces sequence. Use all of these deliberately — over-verification makes tests brittle and hard to refactor.