How do Mockito matchers work?
Mockito matchers are static methods and calls to those methods, which stand in for arguments during calls to when
and verify
.
Hamcrest matchers (archived version) (or Hamcrest-style matchers) are stateless, general-purpose object instances that implement Matcher<T>
and expose a method matches(T)
that returns true if the object matches the Matcher's criteria. They are intended to be free of side effects, and are generally used in assertions such as the one below.
/* Mockito */ verify(foo).setPowerLevel(gt(9000));
/* Hamcrest */ assertThat(foo.getPowerLevel(), is(greaterThan(9000)));
Mockito matchers exist, separate from Hamcrest-style matchers, so that descriptions of matching expressions fit directly into method invocations: Mockito matchers return T
where Hamcrest matcher methods return Matcher objects (of type Matcher<T>
).
Mockito matchers are invoked through static methods such as eq
, any
, gt
, and startsWith
on org.mockito.Matchers
and org.mockito.AdditionalMatchers
. There are also adapters, which have changed across Mockito versions:
- For Mockito 1.x,
Matchers
featured some calls (such asintThat
orargThat
) are Mockito matchers that directly accept Hamcrest matchers as parameters.ArgumentMatcher<T>
extendedorg.hamcrest.Matcher<T>
, which was used in the internal Hamcrest representation and was a Hamcrest matcher base class instead of any sort of Mockito matcher. - For Mockito 2.0+, Mockito no longer has a direct dependency on Hamcrest.
Matchers
calls phrased asintThat
orargThat
wrapArgumentMatcher<T>
objects that no longer implementorg.hamcrest.Matcher<T>
but are used in similar ways. Hamcrest adapters such asargThat
andintThat
are still available, but have moved toMockitoHamcrest
instead.
Regardless of whether the matchers are Hamcrest or simply Hamcrest-style, they can be adapted like so:
/* Mockito matcher intThat adapting Hamcrest-style matcher is(greaterThan(...)) */
verify(foo).setPowerLevel(intThat(is(greaterThan(9000))));
In the above statement: foo.setPowerLevel
is a method that accepts an int
. is(greaterThan(9000))
returns a Matcher<Integer>
, which wouldn't work as a setPowerLevel
argument. The Mockito matcher intThat
wraps that Hamcrest-style Matcher and returns an int
so it can appear as an argument; Mockito matchers like gt(9000)
would wrap that entire expression into a single call, as in the first line of example code.
What matchers do/return
when(foo.quux(3, 5)).thenReturn(true);
When not using argument matchers, Mockito records your argument values and compares them with their equals
methods.
when(foo.quux(eq(3), eq(5))).thenReturn(true); // same as above
when(foo.quux(anyInt(), gt(5))).thenReturn(true); // this one's different
When you call a matcher like any
or gt
(greater than), Mockito stores a matcher object that causes Mockito to skip that equality check and apply your match of choice. In the case of argumentCaptor.capture()
it stores a matcher that saves its argument instead for later inspection.
Matchers return dummy values such as zero, empty collections, or null
. Mockito tries to return a safe, appropriate dummy value, like 0 for anyInt()
or any(Integer.class)
or an empty List<String>
for anyListOf(String.class)
. Because of type erasure, though, Mockito lacks type information to return any value but null
for any()
or argThat(...)
, which can cause a NullPointerException if trying to "auto-unbox" a null
primitive value.
Matchers like eq
and gt
take parameter values; ideally, these values should be computed before the stubbing/verification starts. Calling a mock in the middle of mocking another call can interfere with stubbing.
Matcher methods can't be used as return values; there is no way to phrase thenReturn(anyInt())
or thenReturn(any(Foo.class))
in Mockito, for instance. Mockito needs to know exactly which instance to return in stubbing calls, and will not choose an arbitrary return value for you.
Implementation details
Matchers are stored (as Hamcrest-style object matchers) in a stack contained in a class called ArgumentMatcherStorage. MockitoCore and Matchers each own a ThreadSafeMockingProgress instance, which statically contains a ThreadLocal holding MockingProgress instances. It's this MockingProgressImpl that holds a concrete ArgumentMatcherStorageImpl. Consequently, mock and matcher state is static but thread-scoped consistently between the Mockito and Matchers classes.
Most matcher calls only add to this stack, with an exception for matchers like and
, or
, and not
. This perfectly corresponds to (and relies on) the evaluation order of Java, which evaluates arguments left-to-right before invoking a method:
when(foo.quux(anyInt(), and(gt(10), lt(20)))).thenReturn(true);
[6] [5] [1] [4] [2] [3]
This will:
- Add
anyInt()
to the stack. - Add
gt(10)
to the stack. - Add
lt(20)
to the stack. - Remove
gt(10)
andlt(20)
and addand(gt(10), lt(20))
. - Call
foo.quux(0, 0)
, which (unless otherwise stubbed) returns the default valuefalse
. Internally Mockito marksquux(int, int)
as the most recent call. - Call
when(false)
, which discards its argument and prepares to stub methodquux(int, int)
identified in 5. The only two valid states are with stack length 0 (equality) or 2 (matchers), and there are two matchers on the stack (steps 1 and 4), so Mockito stubs the method with anany()
matcher for its first argument andand(gt(10), lt(20))
for its second argument and clears the stack.
This demonstrates a few rules:
Mockito can't tell the difference between
quux(anyInt(), 0)
andquux(0, anyInt())
. They both look like a call toquux(0, 0)
with one int matcher on the stack. Consequently, if you use one matcher, you have to match all arguments.Call order isn't just important, it's what makes this all work. Extracting matchers to variables generally doesn't work, because it usually changes the call order. Extracting matchers to methods, however, works great.
int between10And20 = and(gt(10), lt(20));
/* BAD */ when(foo.quux(anyInt(), between10And20)).thenReturn(true);
// Mockito sees the stack as the opposite: and(gt(10), lt(20)), anyInt().
public static int anyIntBetween10And20() { return and(gt(10), lt(20)); }
/* OK */ when(foo.quux(anyInt(), anyIntBetween10And20())).thenReturn(true);
// The helper method calls the matcher methods in the right order.The stack changes often enough that Mockito can't police it very carefully. It can only check the stack when you interact with Mockito or a mock, and has to accept matchers without knowing whether they're used immediately or abandoned accidentally. In theory, the stack should always be empty outside of a call to
when
orverify
, but Mockito can't check that automatically.
You can check manually withMockito.validateMockitoUsage()
.In a call to
when
, Mockito actually calls the method in question, which will throw an exception if you've stubbed the method to throw an exception (or require non-zero or non-null values).doReturn
anddoAnswer
(etc) do not invoke the actual method and are often a useful alternative.If you had called a mock method in the middle of stubbing (e.g. to calculate an answer for an
eq
matcher), Mockito would check the stack length against that call instead, and likely fail.If you try to do something bad, like stubbing/verifying a final method, Mockito will call the real method and also leave extra matchers on the stack. The
final
method call may not throw an exception, but you may get an InvalidUseOfMatchersException from the stray matchers when you next interact with a mock.
Common problems
InvalidUseOfMatchersException:
Check that every single argument has exactly one matcher call, if you use matchers at all, and that you haven't used a matcher outside of a
when
orverify
call. Matchers should never be used as stubbed return values or fields/variables.Check that you're not calling a mock as a part of providing a matcher argument.
Check that you're not trying to stub/verify a final method with a matcher. It's a great way to leave a matcher on the stack, and unless your final method throws an exception, this might be the only time you realize the method you're mocking is final.
NullPointerException with primitive arguments:
(Integer) any()
returns null whileany(Integer.class)
returns 0; this can cause aNullPointerException
if you're expecting anint
instead of an Integer. In any case, preferanyInt()
, which will return zero and also skip the auto-boxing step.NullPointerException or other exceptions: Calls to
when(foo.bar(any())).thenReturn(baz)
will actually callfoo.bar(null)
, which you might have stubbed to throw an exception when receiving a null argument. Switching todoReturn(baz).when(foo).bar(any())
skips the stubbed behavior.
General troubleshooting
Use MockitoJUnitRunner, or explicitly call
validateMockitoUsage
in yourtearDown
or@After
method (which the runner would do for you automatically). This will help determine whether you've misused matchers.For debugging purposes, add calls to
validateMockitoUsage
in your code directly. This will throw if you have anything on the stack, which is a good warning of a bad symptom.
How to spy on an object that is instantiated with Callable<T> arg and implements Closeable with Mockito?
You wrote
spy( new CallableExecutor<>( any(), any() ) );
You can't do this. You need to make an actual CallableExecutor
object before you can spy it. And that means passing actual values into its constructor, not passing the output of matcher methods.
The matcher methods work by manipulating an internal structure that Mockito uses to store stubbing and verification information. That's why you can only use them during stubbing or verification.
Pass actual non-matcher arguments to the CallableExecutor
constructor.
Mockito specific matchers like anyString() don't seem to work with overloaded methods?
Mockito.anyString()
does not match null
values, because null
is not an instance of String
.
You're most likely not able to mock the method when replacing any()
with anyString()
simply because one of the method arguments is actually null
rather than a String
.
More information on the topic: https://github.com/mockito/mockito/issues/185
How to handle any other value with Mockito?
You have two options: Matching "any value but one", and overriding stubbing. (I suppose you could also use an Answer for complex custom behavior, but that's overkill for situations like this one.)
Stubbing any value except a given value
Mockito's AdditionalMatchers
class offers a number of useful matchers, including operators such as not
. This would allow you to set behavior for all values except for a specific value (or expression).
when(foo.bar(1)).thenReturn(99);
when(foo.bar(not(eq(1)))).thenThrow(new IllegalArgumentException());
Be careful to note that operators must be used with matchers instead of values, possibly requiring Matchers.eq
as an explicit equals
matcher, due to Mockito's argument matcher stack:
/* BAD */ when(foo.bar(not( 1 ))).thenThrow(new IllegalArgumentException());
/* GOOD */ when(foo.bar(not(eq(1)))).thenThrow(new IllegalArgumentException());
Overriding stubbing
For stubbing, the last-defined matching chain wins. This allows you to set up general test fixture behavior in a @Before
method and override it in individual test cases if you wish, but also implies that order matters in your stubbing calls.
when(foo.baz(anyInt())).thenReturn("A", "B"); /* or .thenReturn("A").thenReturn("B"); */
when(foo.baz(9)).thenReturn("X", "Y");
foo.baz(6); /* "A" because anyInt() is the last-defined chain */
foo.baz(7); /* "B" as the next return value of the first chain */
foo.baz(8); /* "B" as Mockito repeats the final chain action forever */
foo.baz(9); /* "X" because the second chain matches for the value 9 */
foo.baz(9); /* "Y" forever because the second chain action still matches */
Consequently, you should never see the two stubs in the order listed in the question, because if a general match immediately follows a specific match then the specific match will never be used (and may as well be deleted).
Beware that you'll sometimes need to change syntax to doAnswer
when overriding spies or dangerous stubbed behavior. Mockito knows not to count calls to when
for verification or for advancing along thenVerb
chains, but exceptions could still cause your test to fail.
/* BAD: the call to foo.bar(1) will throw before Mockito has a chance to stub it! */
when(foo.bar(anyInt())).thenThrow(new IllegalArgumentException());
when(foo.bar(1)).thenReturn(99);
/* GOOD: Mockito has a chance to deactivate behavior during stubbing. */
when(foo.bar(anyInt())).thenThrow(new IllegalArgumentException());
doReturn(99).when(foo).bar(1);
Mockito: How to match a String and List<String> arguments
Unfortunately, here you cannot easily check what you want to check with matchers.
Mockito matchers work via side-effects, where a call to a matcher tells Mockito to use the matcher rather than testing equality. That means that Mockito matchers don't work at all when nested within objects like Criterion.
verify(mockCriteria).add(
Restrictions.in("type", Arrays.asList("employee", "supervisor"));
In the above, you don't use matchers, you're verifying that mockCriteria.add
is called with an object that equals
the Criterion you specify. However, if the returned Criterion doesn't override equals
(and hashCode
) then it will only test that the instances are the same—which will never be true here, because you're creating a new one in the verify
statement.
verify(mockCriteria).add(Restrictions.in("type", anyList()));
Here, it looks like you're verifying that mockCriteria.add
is called with any list, but anyList()
actually tells Mockito to skip checking for one parameter and returns the dummy value null
. You then create a Criterion where "type" in null
, and then Mockito sees one any
matcher on the stack for a one-argument method call, discards the newly-created invalid Criterion, and just checks that add
was called at all. It looks like everything's working, but your mockCriteria
could receive literally any parameter including null
and the test would still pass. (If you were using a second matcher, or if add
took two parameters, you would get InvalidUseOfMatchersException
instead of your false positive.)
To make this work with Mockito matchers, you would need to write your own Hamcrest matcher that matches the entire Criterion, and then use argThat
to let Mockito match arguments with it.
As Andy Turner mentioned, one way to solve this is to use ArgumentCaptor
:
ArgumentCaptor<Criterion> captor = ArgumentCaptor.forClass(Criterion.class);
verify(mockCriteria).add(captor.capture());
Criterion criterion = captor.getValue();
// assert against criterion
However, be warned that this may be of limited use: Criterion doesn't have a lot of properties you can inspect. You may need to use toString()
, as in this SO question.
PowerMockito / Mockito argument matcher call location issue
Got it - this isn't a PowerMockito thing. This is a standard Mockito thing and is actually by design - the telling point being one word in the error - you cannot use argument matchers outside of verification or stubbing. While I am using them for stubbing, the outside implies more.
This led me to this answer to another question on how matchers work, with the comment of particular importance:
- Call order isn't just important, it's what makes this all work.
Extracting matchers to variables generally doesn't work, because it
usually changes the call order. Extracting matchers to methods,
however, works great.int between10And20 = and(gt(10), lt(20));
/* BAD */ when(foo.quux(anyInt(), between10And20)).thenReturn(true);
// Mockito sees the stack as the opposite: and(gt(10), lt(20)), anyInt().
public static int anyIntBetween10And20() { return and(gt(10), lt(20)); }
/* OK */ when(foo.quux(anyInt(), anyIntBetween10And20())).thenReturn(true);
// The helper method calls the matcher methods in the right order.
Basically have to be careful with the stack, which led me to this, which works and meets my requirements of being able to mock variable number of arguments determined at runtime (the Strings in testDoSomething could all have been pulled from a text file and the method call could be managed via reflection):
@Test
public void testDoSomething() throws Exception {
// Below showing how everything could be externally-driven
mockAnyMethod("SomeClass", "doSomething", "java.lang.Integer");
SomeClass.doSomething(5);
}
public void mockAnyMethod(
final String canonicalClassName,
final String methodName,
final String... canonicalParameterClassNames)
throws Exception {
final Class<?> clazz = Class.forName(canonicalClassName);
PowerMockito.spy(clazz);
PowerMockito.doNothing()
.when(clazz, methodName, getArgumentMatchers(canonicalParameterClassNames));
}
public Object[] getArgumentMatchers(final String... canonicalParameterClassNames)
throws ClassNotFoundException {
final Object[] argumentMatchers = new Object[canonicalParameterClassNames.length];
for (int i = 0; i < canonicalParameterClassNames.length; i++) {
argumentMatchers[i] = any(Class.forName(canonicalParameterClassNames[i]));
}
return argumentMatchers;
}
Related Topics
How to Parse/Format Dates With Localdatetime - Java 8
How to Compare Objects by Multiple Fields
Recursively List Files in Java
How to List the Files Inside a Jar File
Want Current Date and Time in "Dd/Mm/Yyyy Hh:Mm:Ss.Ss" Format
What Do ^ and $ Mean in a Regular Expression
How Many Ways to Click on Webelement in Webdriver
Difference Between Wait() and Sleep()
Polymorphism VS Overriding VS Overloading
Ways to Iterate Over a List in Java
Java: Convert List≪String≫ to a Join()D String
Java Reflection: How to Get the Name of a Variable
Why Does the Foreach Statement Not Change the Element Value
What's the Reason I Can't Create Generic Array Types in Java
Sorting an Arraylist of Objects Using a Custom Sorting Order
How to Update a Jfreechart'S Appearance After It's Been Made Visible