Mixed Mockito Argument Matchers
ID |
java.mockito_arg_matchers_params |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
mockito, reliability, testing |
Description
Reports a Mockito stub (when, given, or the doThrow/doReturn/… when form) or verification (verify) whose call mixes argument matchers (any(), eq(…), argThat(…), a captor’s capture(), …) with plain values.
The report is made only when every argument is classified. An argument that is some other method call — a matcher factory in a shared test-support class, a project Matchers facade — is not read as a plain value, and silences the report for that invocation: reporting one of those is a false alarm, while missing a real mix costs nothing, since Mockito throws InvalidUseOfMatchersException at run time and the test already fails.
Rationale
Mockito requires either every argument of the stubbed or verified call to be a matcher, or none of them. Mixing the two compiles cleanly but throws InvalidUseOfMatchersException the moment the test runs, because Mockito cannot tell which raw values to treat as literal equality checks once any matcher is present.
given(calculator.priceFor(anyInt(), zone, weight)).willReturn(BigDecimal.ZERO);
// anyInt() is a matcher; zone and weight are plain values — throws at test time
Remediation
Wrap every argument in a matcher — eq(…) reproduces plain equality — or drop matchers entirely and pass plain values throughout.
given(calculator.priceFor(anyInt(), eq(zone), eq(weight))).willReturn(BigDecimal.ZERO);
What is not reported
A cast around a matcher call, however many layers deep, is still recognised as a matcher — casting a matcher for overload resolution is common and legitimate. A helper method that itself wraps or forwards to a matcher call is not followed across method or class boundaries, so a call like verify(mock).method(myMatcherHelper(), any()) is not analysed for what it ultimately returns.