I'm basically trying to verify whether the correct parameters are being invoked in a method.
Here's a snippet of the code I'm trying to test:
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.in("type", Arrays.asList("employee", "supervisor");
Verifying this using:
Mockito.verify(mockSession).createCriteria(User.class);
Mockito.verify(mockCriteria).add(Restrictions.in("type", Arrays.asList("employee", "supervisor"));
The first verify statement works. The second doesn't because, I believe, that the JVM detects two different List
objects being compared to. However, when I change the second verify statement to:
Mockito.verify(mockCriteria).add(Restrictions.in("type", Mockito.anyList());
It works like a charm. However, I do want to ensure that the two Strings, employee and supervisor, are inside the List
and that won't happen by using Mockito.anyList()
.
How do I get this to work?
EDIT: Please take note that I do not wish to only verify whether a List has been passed. I want to ensure that the correct Strings are passed inside that List as well
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With