How do you verify a mock was called with specific arguments, including using matchers and ArgumentCaptor?
answer
- literal arg matched by equals
- matchers: any(), eq(), argThat()
- all-or-nothing: matcher for one => matchers for all (wrap with eq)
- ArgumentCaptor.capture() inside verify, getValue() after
- getAllValues() for multiple calls; captor > argThat for messages
basics
~20 sPass the expected argument to verify, e.g. verify(repo).save(user) — it must equal the actual argument. Use matchers like eq(), any(), argThat() for flexible matching, or ArgumentCaptor to grab the real argument and assert on it.
solid answer
~50 sTo verify a call with specific arguments, you supply them inside verify: verify(repo).save(expectedUser) passes only if save was called with an argument equal (by equals) to expectedUser. When you need flexibility, use argument matchers: any() for anything, eq(value) for an exact value, argThat(predicate) for a custom condition. A key rule: if you use a matcher for one argument, you must use matchers for all arguments of that call — mixing a raw value with a matcher throws InvalidUseOfMatchersException; wrap the raw value in eq(). For richer assertions on the captured argument — especially complex objects — use ArgumentCaptor: declare a captor, pass captor.capture() into verify, then captor.getValue() returns the actual argument so you can run normal assertions (assertEquals on fields, etc.). Captor is preferred over argThat when you want clear failure messages and to assert multiple properties. Use getAllValues() to inspect arguments across multiple calls.
code
java · 13 linesArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
service.register("Ada", "[email protected]");
// verify the save happened and capture the argument
verify(repo).save(captor.capture());
User saved = captor.getValue();
assertEquals("Ada", saved.getName());
assertTrue(saved.isActive());
// matcher form (all-or-nothing): wrap literals in eq()
verify(emailSender).send(eq("[email protected]"), eq("welcome"));go deeper
Can pass an expected argument into verify and knows it is matched by equals.
Uses any()/eq()/argThat() correctly, respects the all-or-nothing matcher rule, and captures arguments with ArgumentCaptor.
Chooses captor vs argThat deliberately for failure clarity, handles getAllValues across multiple calls, and knows equals pitfalls with freshly-constructed arguments.
Guides argument-assertion conventions (value objects with proper equals vs captors), minimizing brittle/identity-based matching across the suite.
## Verifying with a literal argument The simplest form passes the expected argument directly: ```java verify(repo).save(expectedUser); ``` Mockito checks the actual argument against `expectedUser` using **`equals`**. So this only works well if the argument type has a meaningful `equals` (a record, a value object, or you assert on a reference you control). If `equals` is identity-based and the code constructs a *new* object, this verify fails even when the object is logically right — that is when you reach for matchers or a captor. ## Argument matchers Matchers (from `org.mockito.ArgumentMatchers`) let you describe the argument loosely: - `any()` / `anyString()` / `anyLong()` — any value of that type. - `eq(value)` — equal to value (the matcher form of a literal). - `argThat(x -> x.getAge() > 18)` — a custom predicate. - `isNull()`, `isNotNull()`, `contains("x")`, etc. ```java verify(repo).save(argThat(u -> u.getName().equals("Ada"))); verify(emailSender).send(any(), eq("welcome")); ``` ## The all-or-nothing matcher rule Mockito implements matchers via a side stack, so you **cannot mix** raw values and matchers in one call. This is illegal: ```java verify(svc).update(123, eq("name")); // InvalidUseOfMatchersException ``` Fix by wrapping the raw value: ```java verify(svc).update(eq(123), eq("name")); ``` If any argument uses a matcher, **all** must. ## ArgumentCaptor — capture then assert When you want to inspect a complex argument or assert multiple properties with clear failure messages, capture it: ```java ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class); verify(repo).save(captor.capture()); User saved = captor.getValue(); assertEquals("Ada", saved.getName()); assertTrue(saved.isActive()); ``` - `captor.capture()` goes *inside* the verify call (it is itself a matcher). - `getValue()` returns the last captured argument; `getAllValues()` returns a list across multiple captured calls. ## Captor vs argThat Both can express custom conditions. Prefer **ArgumentCaptor** when you want: - to assert several properties with normal, readable assertions, and - a good failure message (a failing `assertEquals` prints expected vs actual; a failing `argThat` predicate just says verification failed). Prefer **argThat** for a quick inline boolean condition when you don't need the captured object afterwards. ## Multiple calls With `verify(repo, times(3)).save(captor.capture())`, `captor.getAllValues()` returns all three arguments in call order — handy to assert a sequence of saved entities. ## @Captor In a `MockitoExtension`/`@ExtendWith` test you can declare `@Captor ArgumentCaptor<User> captor;` instead of `forClass`, which also preserves generic type info.
- Why does verify(svc).update(123, eq("name")) throw, and how do you fix it?Mockito forbids mixing a raw value with a matcher in one call. Wrap the raw value: verify(svc).update(eq(123), eq("name")).
- When should you prefer ArgumentCaptor over argThat?When you need to assert several properties of the argument or want a clear expected-vs-actual failure message; captor.getValue() lets you run normal assertions. argThat is fine for a quick inline boolean condition.
saying these in an interview costs you the question
- Mixing raw values and matchers in one verify call (throws InvalidUseOfMatchersException)
- Verifying with a literal object whose equals is identity-based and expecting it to match a freshly constructed argument
- Putting captor.capture() outside verify, or calling getValue() before the verify ran
- Using argThat for multi-property checks and getting an unhelpful failure message instead of using a captor