When writing Mockito stubs and verifications, when should you wrap a plain value in ArgumentMatchers.eq(), and when is passing the raw value directly the better style?
answer
- eq() = Equals matcher + stack entry
- Only needed when the call already has a matcher
- Raw args are compared with equals() anyway
- No equals() override means identity comparison
- capture() is a matcher too - wrap siblings
basics
~20 sUse eq() only when the same call already uses another matcher, because matchers and raw values cannot be mixed. If no argument needs a wildcard, pass plain values - eq() everywhere is noise with identical behaviour.
solid answer
~40 s`eq(x)` matches arguments equal to `x` - exactly what a raw value does - but it also registers an entry on Mockito's matcher stack. Since one invocation must use zero matchers or a matcher per argument, `eq()` exists to promote literals in a call that already needs `any()`, `argThat()`, or a captor. So the rule of thumb: - No matcher needed anywhere in the call: `verify(repo).save(user)` - plainest and most readable. - At least one matcher: promote everything, `verify(repo).find(eq(42), any(Filter.class))`. Two caveats worth naming. `eq()` uses `equals()`, so for a class without a meaningful `equals()` it degrades to identity comparison - use `same()` for identity on purpose or an `ArgumentCaptor`/`argThat` for field-level assertions. And `eq(null)` is legal but `isNull()` reads better.
code
java · 8 lines// nothing needs a wildcard -> raw values
verify(repo).save(user);
// one wildcard -> promote the rest
verify(repo).find(eq(42), any(Filter.class));
// capture() is a matcher, so id must be eq()
verify(repo).update(eq(42L), captor.capture());go deeper
State the rule: eq() is how you keep a literal legal in a call that already uses a matcher, and plain values are fine otherwise.
Add that eq() delegates to equals(), so value types without equals() silently degrade to identity comparison, and mention same() and isNull() as intent-revealing alternatives.
Discuss failure-message quality and mutable arguments: prefer captors or argThat for object-shaped assertions so a mismatch reports the offending field rather than a toString diff.
Position it as a team convention: agree when equality-based verification is acceptable versus capture-and-assert, and require equals/hashCode on verification-relevant value types so tests do not encode accidental identity semantics.
## What eq() is `ArgumentMatchers.eq(value)` returns a dummy (`null`, `0`, `false`) after pushing an `Equals` matcher onto Mockito's thread-local matcher stack. That matcher later evaluates `value.equals(actualArgument)` - the identical comparison Mockito applies when you pass the value raw. So `eq()` never changes *what* matches; it changes only the bookkeeping. ## Why it exists at all Because of the all-or-none rule: within a single mock invocation Mockito accepts zero matchers (raw arguments compared with equals) or exactly one matcher per argument. There is no middle ground, since matchers return dummies indistinguishable from real values. So the moment one argument needs a wildcard, every other argument must become a matcher too - and `eq()` is the wrapper that makes a literal into one. ```java verify(repo).find(eq(42), any(Filter.class)); // required verify(repo).save(user); // eq() would be pure noise ``` ## When raw is better If the call needs no wildcard, pass raw values. It is shorter, needs no static import, and is what most codebases do. Reviewers reading `verify(mailer).send(eq("[email protected]"), eq(subject))` reasonably ask what the matcher is for; the answer is nothing, which is a small readability tax on every reader. ## When eq() is required 1. **Mixed calls** - anything alongside `any()`, `anyString()`, `argThat(...)`, `isNull()`, or `captor.capture()`. 2. **Captor calls** - `verify(repo).update(eq(id), captor.capture())`: `capture()` is itself a matcher, so the id must be wrapped. 3. **Generic-heavy code** where an explicit `eq(...)` with a type witness (`ArgumentMatchers.<List<String>>eq(list)`) helps inference. ## Sharp edges **equals() semantics.** `eq()` delegates to the argument's `equals()`. A DTO without `equals()` falls back to `Object.equals`, i.e. reference identity, so a stub that looks value-based silently becomes identity-based and never matches an object rebuilt inside the code under test. Options: implement `equals()`, use `argThat(...)` on the fields you care about, or capture and assert with AssertJ - the last usually gives the best failure message. **Arrays.** `eq(new int[]{1,2})` compares with `Arrays.equals` via Mockito's internal `Equality` helper, which is friendlier than raw `equals()` on arrays - but do not assume that for arbitrary array-holding value objects. **Mutable arguments.** If the production code mutates the object after the call, `eq()` compares the mutated state at verification time, because the mock stores a reference. That is a classic source of "verification passes/fails inexplicably"; capture-and-assert or a defensive copy is the remedy. **Nulls.** `eq(null)` compiles and works, but `isNull()` states intent and avoids ambiguity in overload resolution. **Identity vs equality.** `same(x)` matches only if the argument is the same reference. Use it deliberately when identity is the contract (for example a cached singleton), not as a workaround for a missing `equals()`. ## Interview framing A junior answer states the mixing rule and the fix. A stronger answer adds the style guidance (do not wrap when nothing else is a matcher) and the `equals()` trap - that `eq()` is only as good as the argument type's equality contract, which is exactly why captors and `argThat` exist for value-shaped assertions.
- A stub written with eq(dto) never matches, although the production code clearly passes an equal-looking DTO. What is the likely cause?The DTO almost certainly does not override equals(), so eq() falls back to Object.equals - reference identity - and the instance built inside the code under test is a different object. Fix by implementing equals/hashCode on the value type, or by switching to argThat/ArgumentCaptor and asserting the fields that matter, which also produces a far clearer failure message.
- How do eq() and same() differ?eq(x) matches when x.equals(actual), so any equal instance passes; same(x) matches only when the argument is the identical reference. Use same() when identity is genuinely part of the contract, such as verifying that a cached or injected instance was forwarded untouched, not as a patch for a missing equals() implementation.
saying these in an interview costs you the question
- Wrapping every argument in eq() by default and calling it best practice
- Believing eq() compares fields reflectively rather than delegating to equals()
- Thinking eq() is required whenever any matcher appears anywhere in the test rather than in that one call
- Using eq() on a mutable object and not realising the comparison happens later against possibly mutated state
- Saying eq(null) is illegal - it works, though isNull() is clearer