Mockito verify() — How Over-Verification Halved Payments
A renamed method caused verify() to pass on a dead mock, halving payments in production.
- Mockito verify() asserts that an expected interaction with a mock actually occurred
- Default mode checks exactly one call; use times(n), atLeastOnce(), never() for other counts
- Argument matchers (any(), eq(), argThat()) give flexible matching but must be used consistently across all arguments
- ArgumentCaptor captures generated values (UUIDs, timestamps) for post-hoc assertions
- Over-verifying internal calls creates brittle tests that break on refactoring – only verify meaningful side effects
Mockito verify() is how you assert behaviour, not state. When a test checks that account.getBalance() equals 1000, that's asserting state. When a test checks that notificationService.sendEmail() was called exactly once with the right email address, that's asserting behaviour — and verify() is the tool for it.
There are two schools of thought on verify() in unit tests. One says: verify everything — assert that every collaborator method was called as expected. The other says: verify only the meaningful side effects — calling a payment processor, sending a notification — and trust that state assertions cover the rest.
After ten years of writing and reviewing Java tests, I'm firmly in the second camp. Verifying every internal method call ties your tests to the implementation rather than the contract. When you refactor, tests break for reasons unrelated to correctness. Verify interactions that represent side effects your callers care about. Leave implementation details to state assertions.
Basic verify() and Verification Modes
The basic verify(mock).method(args) asserts the method was called exactly once with the given arguments. Verification modes control the count: times(n), atLeastOnce(), atLeast(n), atMost(n), .never()
verify(mock, times(1)).method(). verify(mock).method() is equivalent. Only specify times(n) when n is not 1.TooManyActualInvocations when a method is called in a loop with off-by-one errors.atMost(n) for loops where exact count varies, and log the invocation count during debugging.times, never, atLeast) based on the contract, not convenience.never() to explicitly assert side effects should not happen.Argument Matchers in verify()
Exact argument matching works for primitives and objects with correct equals() implementations. For everything else, Mockito's argument matchers give you flexibility: any(), anyString(), eq(), argThat() for custom predicates.
The rule that trips people up: you cannot mix exact values and matchers in the same method call. If one argument uses a matcher, all arguments must use matchers. Wrap exact values in .eq()
anyString() for one argument, you must use matchers for all arguments of that method call. Wrap literal values with eq(). Forgetting this causes InvalidUseOfMatchersException at runtime.InvalidUseOfMatchersException when they add one matcher without wrapping other args.eq() when using any matcher.argThat() is your escape hatch for complex predicates – but keep them simple and testable.Using ArgumentCaptor for Generated Values
When the code under test generates a value (an ID, a timestamp, a computed field) and passes it to a collaborator, you can't use because you don't know the value at test-write time. eq()ArgumentCaptor captures the actual argument that was passed, so you can assert on its structure or properties after the fact.
This is especially useful for generated UUIDs, timestamps, or objects with deep fields.
captor.getAllValues() returns a List of all captured arguments. Use that to assert on each call's parameters.ArgumentCaptor catches these because you can assert on the generated field directly.captor to validate it; don't assume it's correct.ArgumentCaptor when you cannot predict the exact argument value.captor.capture() in verify(), then assert with standard assertions.captor.getAllValues() and iterate.Order Verification with InOrder
Sometimes you need to verify that methods were called in a specific sequence. InOrder verifier lets you enforce call order across one or more mocks.
Use it for scenarios like: user registration must trigger audit log before sending confirmation email. If order doesn't matter, don't use InOrder – it over-specifies.
- Use InOrder when the order of calls is part of the business requirement.
- Do not use InOrder for calls that happen in separate threads or asynchronous tasks – the order is non-deterministic.
- InOrder works across multiple mocks; pass them in the order you expect them to be called.
- InOrder only checks relative order of the verified methods, not that no other calls happened in between.
Best Practices: What to Verify and What Not to Verify
The most common mistake with verify() is overuse. Every verify(mock).method() is a statement that your test knows about internal wiring. That's a liability during refactoring.
Verify only: - Side effects that cross a service boundary (sending email, publishing event, writing to external system). - Calls that represent business transactions (payment, debit, credit). - Calls that are part of a contract with an external system.
Do not verify: - Calls between internal methods of the same class. - Getters or setters (test state instead). - Calls that happen with 100% certainty under the test conditions (if the method under test is simple, trust state assertions).
When in doubt, ask: "If this internal call moves to a different class, should my test still exist?" If yes, verify the boundary. If no, don't verify.
- Boundary: calls to external APIs, databases, message queues, email, etc.
- Implementation: calls between private methods, internal calculations, data transformations.
- If you verify internal calls, you're testing the 'how', not the 'what'. The 'what' is the result and the external side effects.
- Refactoring internal code should not require changing tests – unless the external contracts change.
Brittle Tests Masked a Payment Logic Bug in Production
verify() calls passed, the payment logic was correct. They had verified every single internal call in the chain, including ones that were later removed.- Verify interactions that cross a service boundary – not internal implementation wiring.
- Over-verification makes refactoring dangerous: you either break tests or weaken coverage.
- Use
verifyNoMoreInteractions()sparingly – it's often a sign of over-specification.
WantedButNotInvoked: method was never calledSystem.out.println in the production code, or use a breakpoint in the mock method (IDEA allows setting breakpoints on mock calls).TooManyActualInvocations: method called more times than expectedverify(mock, times(n)) with the exact expected count, or use atMost(n) if exact count is not critical. Add logging to count calls.ArgumentsAreDifferent: arguments don't matchArgumentCaptor to capture the actual passed argument and print it. Compare with expected value. Check if equals() is implemented correctly on the argument type, or use argThat() with a predicate.InvalidUseOfMatchersException: mixing matchers and exact valueseq() if at least one matcher is used anywhere in the same method call.Key takeaways
any(), anyString(), eq(), argThat()) must be used consistentlyCommon mistakes to avoid
5 patternsVerifying every internal method call
Mixing exact values and argument matchers without eq()
InvalidUseOfMatchersException at runtime with a confusing error message.any(), argThat()), wrap all exact values in eq().Calling verify() before the system under test executes
verify() runs before any interaction happens – Mockito checks past interactions, not future ones.verify() calls after the Act step, never before it.Not using ArgumentCaptor for generated values
ArgumentsAreDifferent because the expected UUID or timestamp doesn't match what was passed.ArgumentCaptor to capture the actual generated value and assert on its properties (e.g., non-null, correct type, within time range).Using InOrder for asynchronous code
Interview Questions on This Topic
What is the difference between Mockito when() and verify()?
verify() is used to assert that a method was called (and how many times). when() sets up behaviour for the test; verify() checks interactions afterwards. They serve different phases of a test: Arrange (when) vs Assert (verify).Frequently Asked Questions
That's Advanced Java. Mark it forged?
3 min read · try the examples if you haven't