Mockito match any class argument
Is there a way to match any class argument of the below sample routine?
class A {
public B method(Class<? extends A> a) {}
}
How can I always return a new B()
regardless of which class is passed into method
? The following attempt only works for the specific case where A
is matched.
A a = new A();
B b = new B();
when(a.method(eq(A.class))).thenReturn(b);
EDIT: One solution is
(Class<?>) any(Class.class)
Solution 1:
Two more ways to do it (see my comment on the previous answer by @Tomasz Nurkiewicz):
The first relies on the fact that the compiler simply won't let you pass in something of the wrong type:
when(a.method(any(Class.class))).thenReturn(b);
You lose the exact typing (the Class<? extends A>
) but it probably works as you need it to.
The second is a lot more involved but is arguably a better solution if you really want to be sure that the argument to method()
is an A
or a subclass of A
:
when(a.method(Matchers.argThat(new ClassOrSubclassMatcher<A>(A.class)))).thenReturn(b);
Where ClassOrSubclassMatcher
is an org.hamcrest.BaseMatcher
defined as:
public class ClassOrSubclassMatcher<T> extends BaseMatcher<Class<T>> {
private final Class<T> targetClass;
public ClassOrSubclassMatcher(Class<T> targetClass) {
this.targetClass = targetClass;
}
@SuppressWarnings("unchecked")
public boolean matches(Object obj) {
if (obj != null) {
if (obj instanceof Class) {
return targetClass.isAssignableFrom((Class<T>) obj);
}
}
return false;
}
public void describeTo(Description desc) {
desc.appendText("Matches a class or subclass");
}
}
Phew! I'd go with the first option until you really need to get finer control over what method()
actually returns :-)
Solution 2:
There is another way to do that without cast:
when(a.method(Matchers.<Class<A>>any())).thenReturn(b);
This solution forces the method any()
to return Class<A>
type and not its default value (Object
).
Solution 3:
If you have no idea which Package you need to import:
import static org.mockito.ArgumentMatchers.any;
any(SomeClass.class)
OR
import org.mockito.ArgumentMatchers;
ArgumentMatchers.any(SomeClass.class)
Solution 4:
How about:
when(a.method(isA(A.class))).thenReturn(b);
or:
when(a.method((A)notNull())).thenReturn(b);
Solution 5:
the solution from millhouse is not working anymore with recent version of mockito
This solution work with java 8 and mockito 2.2.9
where ArgumentMatcher
is an instanceof org.mockito.ArgumentMatcher
public class ClassOrSubclassMatcher<T> implements ArgumentMatcher<Class<T>> {
private final Class<T> targetClass;
public ClassOrSubclassMatcher(Class<T> targetClass) {
this.targetClass = targetClass;
}
@Override
public boolean matches(Class<T> obj) {
if (obj != null) {
if (obj instanceof Class) {
return targetClass.isAssignableFrom( obj);
}
}
return false;
}
}
And the use
when(a.method(ArgumentMatchers.argThat(new ClassOrSubclassMatcher<>(A.class)))).thenReturn(b);