Argument matchers are mainly used for performing flexible verification and stubbing in Mockito. It extends ArgumentMatchers class to access all the matcher functions. Mockito uses equal() as a legacy method for verification and matching of argument values.
Mockito allows us to create mock objects and stub the behavior for our test cases. We usually mock the behavior using when() and thenReturn() on the mock object.
Since Mockito any(Class) and anyInt family matchers perform a type check, thus they won't match null arguments.
mockito. Matchers is deprecated, ArgumentMatchers should be used instead.
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 :-)
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
).
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)
How about:
when(a.method(isA(A.class))).thenReturn(b);
or:
when(a.method((A)notNull())).thenReturn(b);
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);
None of the examples above worked for me, as I'm required to mock one method multiple times for different class type parameters.
Instead, this works.
//Handle InstrumentType.class
Mockito.doReturn(new InstrumentTypeMapper() {
@Override
public InstrumentType map(String sourceType) throws Exception {
return InstrumentType.Unknown;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat(new ArgumentMatcher<Class<InstrumentType>>() {
@Override
public boolean matches(Class<InstrumentType> argument) {
return InstrumentType.class.isAssignableFrom(argument);
}
}));
//Handle InstrumentSubType.class
Mockito.doReturn(new InstrumentSubTypeMapper() {
@Override
public InstrumentSubType map(String sourceType) throws Exception {
return InstrumentSubType.istNone;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat(new ArgumentMatcher<Class<InstrumentSubType>>() {
@Override
public boolean matches(Class<InstrumentSubType> argument) {
return InstrumentSubType.class.isAssignableFrom(argument);
}
}));
This is the short version:
Mockito.doReturn(new InstrumentTypeMapper() {
@Override
public InstrumentType map(String sourceType) throws Exception {
return InstrumentType.Unknown;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat((ArgumentMatcher<Class<InstrumentType>>) InstrumentType.class::isAssignableFrom));
Mockito.doReturn(new InstrumentSubTypeMapper() {
@Override
public InstrumentSubType map(String sourceType) throws Exception {
return InstrumentSubType.istNone;
}
}).when(mappingLoader).load(any(ServiceCode.class), argThat((ArgumentMatcher<Class<InstrumentSubType>>) InstrumentSubType.class::isAssignableFrom));
As you can see, I'm using custom ArgumentMatchers together with argThat, not sure if there is a shorter way that also works.
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