When should you prefer ArgumentCaptor over an argThat matcher, and vice versa?
answer
- argThat = matching/stubbing; captor = post-hoc assertion
- Captors can't stub
- Captor → readable multi-field AssertJ + failure messages
- argThat for simple inline conditions and stubbing
- All-or-nothing matcher rule (use eq for literals)
basics
~20 sUse a captor to assert on an argument after the call with normal assertions, especially for complex objects or sequences. Use argThat when you need the condition during stubbing or want the matching logic inline as part of verify.
solid answer
~50 sBoth inspect arguments, but they answer different questions. argThat(predicate) is an inline matcher: it makes the verify or the stub match only when the argument satisfies a condition, and you can use it both in verify(...) and in when(...) stubbing. A captor doesn't decide matching — it grabs the actual argument so you can assert on it afterward with full JUnit/AssertJ assertions. Prefer the captor when: the assertion is rich (many fields), you want readable failure messages, or you need to inspect a sequence via getAllValues(). Prefer argThat when: you need the predicate to drive stubbing behaviour (captors can't stub), or the check is a simple one-liner that reads well inline. A classic rule of thumb: use argThat for stubbing/matching, use captors for verification + detailed post-hoc assertions. Overusing captors (capturing everything) can hurt readability.
go deeper
Knows both can check arguments but may not yet articulate the stubbing distinction.
States that argThat works in stubbing and verify while captors are verify-only, and picks a captor for multi-field assertions.
Gives a clear decision rubric (readability, failure messages, sequences, stubbing), knows the all-matchers rule, and avoids over-capturing.
Sets team guidance balancing inline matchers vs captors, considers test-suite maintainability and failure diagnostics, and recognizes capturing as a design signal of how much the test couples to internals.
## Two tools, two jobs **`argThat(matcher)`** is an **argument matcher**: a predicate you place in the argument slot of a `verify(...)` or a stubbing `when(...)`. The call matches only if the actual argument satisfies the predicate. ```java verify(repo).save(argThat(u -> u.getEmail().equals("[email protected]"))); // or for stubbing: when(repo.findBy(argThat(q -> q.isActive()))).thenReturn(result); ``` **`ArgumentCaptor`** does **not** decide whether a call matches; it **records** the actual argument so you can assert on it after the verification with ordinary assertions. ```java verify(repo).save(captor.capture()); User u = captor.getValue(); assertThat(u.getEmail()).isEqualTo("[email protected]"); assertThat(u.getRoles()).containsExactly(Role.USER); ``` ## Decision guide **Prefer a captor when:** - You want to assert **many fields** of a complex object — captor + AssertJ reads far better than a giant boolean in `argThat`. - You want **clear failure messages**: an `argThat` predicate that returns false just says "argument did not match"; AssertJ on a captured value tells you *which field* differed. - You need to inspect a **sequence** of calls (`getAllValues()`). - The check naturally happens **after** the act, not as part of matching. **Prefer `argThat` (or other matchers) when:** - You need the condition during **stubbing** — captors only work with `verify`, they can't influence what a mock returns. To make a stub respond differently based on the argument, you must use a matcher. - The condition is a **simple one-liner** that reads cleanly inline. - You want the test to **fail at the verify line** when the argument is wrong, rather than later at an assertion. ## Important gotchas - **Matcher rule**: if you use *any* matcher (including `capture()` or `argThat`) for one argument, **all** arguments in that call must be matchers (use `eq(...)` for the literal ones). - **Captors don't stub.** A very common confusion: people try to use a captor to make a mock return something — impossible. Stubbing needs matchers or concrete values. - **Don't over-capture.** Capturing arguments you don't assert on adds noise. Capture only what you check. ## Mental model > `argThat` = "only match when …" (works for matching *and* stubbing). > captor = "let the call match, then hand me the real argument to inspect" (verification only).
- Can you use an ArgumentCaptor to make a stub return different values per argument?No. Captors only work with verify and don't influence behaviour. Argument-dependent stubbing requires matchers like argThat or an Answer.
- Why might a captor give better test failures than argThat for a complex object?argThat just reports a match failure; with a captor you assert each field with AssertJ, so the failure message pinpoints exactly which field was wrong.
- If one argument uses capture(), what must the other arguments use?They must also be matchers — wrap literal values in eq(...). Mockito forbids mixing raw values and matchers in one call.
saying these in an interview costs you the question
- Claiming a captor can drive stubbing / change a mock's return value
- Using argThat with heavy multi-field logic where a captor reads better
- Mixing raw values and matchers in the same call without eq(...)
- Capturing everything regardless of what you assert