Question

I want to do this:

when(myObject.getEntity(1l,usr.getUserName()).thenReturn(null);
when(myObject.getEntity(1l,Constants.ADMIN)).thenReturn(null);

in one line with matchers. So, I have this code:

import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import static org.mockito.AdditionalMatchers.*;

[...]

User usr = mock(usr);

[...]

when(myObject.getEntity(
    eq(1l), 
    or(eq(usr.getUserName()),eq(Constants.ADMIN))
    )
).thenReturn(null);

But when I use the Or matcher, JUnit fails:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 1 recorded.
This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.
    at blah.blah.MyTestClass.setup(MyTestClass:The line where I use the when & or matcher)
... more stacktrace ...

What I'am doing wrong?

Thanks!

Was it helpful?

Solution

Because usr is a mock, that inline method call usr.getUserName() is the part that's throwing you off. You can't call a mocked method in the middle of stubbing another method, for reasons specific to Mockito's implementation and syntax cleverness.

when(myObject.getEntity(
    eq(1l), 
    or(eq(usr.getUserName()),eq(Constants.ADMIN))
    )
).thenReturn(null);

Calls to Mockito matchers like eq and or actually return dummy values like 0 and null, and—as side effects—they add their Matcher behavior to a stack called ArgumentMatcherStorage. As soon as Mockito sees a method call on a mock, it examines the stack to see if it's empty (i.e. check equality of all arguments) or the length of the parameter list of the called method (i.e. use the matchers on the stack, one per parameter). Anything else is an error.

Given Java's order of evaluation, your code evaluates eq(1l) for the first parameter, then usr.getUserName() for the second parameter—the first parameter of or. Note that getUserName takes no arguments, so there are 0 matchers expected, and 1 recorded.

This should work fine:

String userName = usr.getUserName(); // or whatever you stubbed, directly
when(myObject.getEntity(
    eq(1l), 
    or(eq(userName),eq(Constants.ADMIN))
    )
).thenReturn(null);

To see more about how Mockito matchers work under the covers, see my other SO answer here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top