skip to content

Custom Matchers (argThat)

When built-ins aren't enough: argThat with a lambda or ArgumentMatcher implementation, primitive variants, and combinators from AdditionalMatchers. Interviewers ask when you'd write a custom matcher versus capturing the argument and asserting on it.

on this pageshow

questions

4

Mockito's built-in matchers cannot express a condition like 'an Order whose total exceeds 100 and whose status is PENDING'. How do you match an argument on an arbitrary condition when stubbing or verifying with Mockito?

level: middleimportance: must knowfreq 45%

answer

  1. argThat(ArgumentMatcher) - boolean matches(T)
  2. functional interface -> lambda
  3. pure predicate, no assertions inside
  4. primitives: intThat / longThat / doubleThat
  5. AdditionalMatchers: gt, lt, and, or, not

basics

~20 s

Use argThat(ArgumentMatcher) with a predicate: verify(repo).save(argThat(o -> o.total() > 100 && o.status() == PENDING)). ArgumentMatcher is a functional interface with one boolean matches(T) method, so a lambda works. It composes with the built-in matchers in the same call.

solid answer

~50 s

argThat(ArgumentMatcher<T>) is the extension point. ArgumentMatcher is a single-method functional interface - boolean matches(T argument) - so a lambda or a small named class both work, and the matcher is used identically in stubbing and verification. Two things to keep in mind. The predicate must be pure: Mockito may call it more than once, for every recorded invocation and again while building a failure message, so no side effects and no assertions inside it - a throwing matcher derails Mockito's invocation matching and yields a confusing error. Second, a lambda's toString() is meaningless, so a failed verification prints something like Test$$Lambda$14@6d06d69c; a named class overriding toString() makes the report readable. Mockito also ships AdditionalMatchers - gt, lt, geq, leq, and, or, not, aryEq - which cover common numeric and boolean combinations without writing a predicate at all.

code

java · 9 lines
java
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.*;

verify(repo).save(argThat(o ->
        o.total().compareTo(new BigDecimal("100")) > 0
                && o.status() == Status.PENDING));

when(pricing.quote(argThat(r -> r.items().size() > 10)))
        .thenReturn(bulkQuote);

go deeper

for a junior

Show argThat with a lambda and say ArgumentMatcher has one boolean matches(T) method.

for a middle

Add the purity rules, the primitive variants, and that it works in stubbing to discriminate between calls.

for a senior

Discuss failure diagnosability and when a predicate is the wrong tool because it collapses the reason for failure to a boolean.

for a principal

Frame reusable named domain matchers as shared test vocabulary, and set the boundary between selecting an invocation and asserting its content.

## The API org.mockito.ArgumentMatcher<T> declares one method: boolean matches(T argument). ArgumentMatchers.argThat(ArgumentMatcher<T>) registers it and returns a dummy value, exactly like any() or eq(). Because the interface is functional, the common form is a lambda: verify(repo).save(argThat(o -> o.total().compareTo(HUNDRED) > 0 && o.status() == PENDING)); It works in stubbing too: when(pricing.quote(argThat(r -> r.items().size() > 10))).thenReturn(bulkQuote). That is a capability plain assertions do not have - a matcher can make two stubs on the same method behave differently depending on the argument, and can pick out which of several recorded invocations you meant. ## Rules the predicate must obey Mockito calls matches() while comparing the recorded invocations, and may call it repeatedly - once per candidate invocation, and again when composing a verification failure report. Therefore: - No side effects. Do not mutate the argument, record state, or count calls inside the matcher. - No assertions. Throwing from matches() does not produce a nice assertion failure; it escapes in the middle of Mockito's matching machinery and usually surfaces as an unrelated-looking error. If you want rich assertion messages, assert on the value outside the verification instead. - Handle unexpected input. In stubbing the matcher can see arguments from calls you did not anticipate, including null. A predicate that dereferences blindly will NullPointerException on an unrelated call. ## Primitive parameters argThat is generic and returns null, so using it directly for a primitive parameter throws NullPointerException during unboxing. Mockito ships primitive-typed siblings for exactly this: intThat, longThat, shortThat, byteThat, charThat, floatThat, doubleThat, booleanThat, each taking an ArgumentMatcher of the boxed type and returning a safe default. ## AdditionalMatchers before writing your own org.mockito.AdditionalMatchers covers a lot of what people hand-roll: gt, lt, geq, leq and cmpEq for Comparable and numeric arguments, eq(double, delta) for floating point tolerance, aryEq for arrays, find(regex) for strings, and the combinators and, or, not that compose two matchers on the same argument. verify(meter).record(and(gt(0L), lt(1000L))) reads better than a predicate and produces a better message. ## Named matchers over lambdas A lambda is fine for a one-off. When the same condition appears in several tests, a small named class - class PendingOrderOver implements ArgumentMatcher<Order>, with a meaningful toString() - is worth the few lines: it names the domain concept, is reusable, and gives a readable failure message instead of a synthetic lambda class name. ## Where it does not fit If what you actually want is a rich assertion over the argument - several fields, a diff on failure, soft assertions - a predicate is the wrong shape, because it collapses everything to a boolean and loses the explanation. Use a predicate matcher when you need to select or discriminate an invocation; use extracted-value assertions when you need to describe what was wrong.

  • Is it acceptable to put assertions inside an argThat predicate so you get a good failure message?
    No. Mockito may invoke the matcher several times, including while building its own failure report, and an exception thrown from matches() escapes into the matching machinery rather than being reported as a clean assertion failure. Keep the predicate a pure boolean and put rich assertions outside the verification.
  • Can argThat be used in stubbing as well as verification, and does that change anything?
    Yes, it works in both, and stubbing is where it is most powerful because you can give the same method different answers depending on the argument. The extra care needed is that the predicate will be evaluated against every call to that method, including unexpected or null arguments, so it must be null-safe and side-effect free.

saying these in an interview costs you the question

  • Putting assertThat or assertions inside the matcher predicate
  • Assuming the predicate runs exactly once per call
  • Dereferencing the argument without a null check in a stubbing matcher
  • Using argThat directly on a primitive parameter and being surprised by the NPE
  • Hand-rolling range predicates when AdditionalMatchers.gt/lt exist

context

open as a page

A Mockito verification written as verify(service).setRetryCount(argThat(n -> n > 3)) blows up with a NullPointerException before any assertion is reported, on a method whose parameter is a primitive int. What is happening, and which Mockito API fixes it?

level: middleimportance: should knowfreq 30%

basics

~20 s

argThat is generic and returns null. Java must unbox that null into the primitive int parameter, which throws NullPointerException before Mockito compares anything. Use intThat(n -> n > 3) - and the siblings longThat, doubleThat, booleanThat and so on - which return a primitive default.

open as a page

A Mockito verification using a lambda-based custom argument matcher fails, and the report prints something like Test$$Lambda$14/0x0000000800c0a440@6d06d69c instead of anything readable. How do you make custom argument matchers produce diagnosable failure messages?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Mockito prints the matcher's toString() in the 'Argument(s) are different' report, and a lambda's toString() is the synthetic class name. Implement ArgumentMatcher as a named class overriding toString() with a human description, or drop the matcher and assert on the extracted value instead.

open as a page

In a large test suite using Mockito, argument assertions can live inside the verification as custom predicate matchers, or be pulled out and asserted separately on the recorded value. How do you decide which, and what does each choice cost in diagnosability and coupling?

level: principalimportance: should knowfreq 25%

basics

~20 s

Use a predicate matcher when the condition must select which invocation or which stubbed behaviour applies. Pull the assertion out when you need a readable explanation of what was wrong. Matchers discriminate, assertions explain - and matchers also work in stubbing, where extracted assertions cannot.

open as a page