Stubbing a method that takes Class<T> as parameter with Mockito

JavaClassGenericsMockingMockito

Java Problem Overview


There is a generic method that takes a class as parameter and I have problems stubbing it with Mockito. The method looks like this:

public <U extends Enum<U> & Error, T extends ServiceResponse<U>> T validate(
    Object target, Validator validator, Class<T> responseClass,
    Class<U> errorEnum);

It's god awful, at least to me... I could imagine living without it, but the rest of the code base happily uses it...

I was going to, in my unit test, stub this method to return a new empty object. But how do I do this with mockito? I tried:

when(serviceValidatorStub.validate(
    any(), 
    isA(UserCommentRequestValidator.class), 
    UserCommentResponse.class, 
    UserCommentError.class)
).thenReturn(new UserCommentResponse());

but since I am mixing and matching matchers and raw values, I get "org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!"

Java Solutions


Solution 1 - Java

The problem is, you cannot mix argument matchers and real arguments in a mocked call. So, rather do this:

when(serviceValidatorStub.validate(
    any(),
    isA(UserCommentRequestValidator.class),
    eq(UserCommentResponse.class),
    eq(UserCommentError.class))
).thenReturn(new UserCommentResponse());

Notice the use of the eq() argument matcher for matching equality.

see: https://static.javadoc.io/org.mockito/mockito-core/1.10.19/org/mockito/Matchers.html#eq(T)

Also, you could use the same() argument matcher for Class<?> types - this matches same identity, like the == Java operator.

Solution 2 - Java

Just in order to complete on the same thread, if someone want to stubb a method that takes a Class as argument, but don't care of the type, or need many type to be stubbed the same way, here is another solution:

private class AnyClassMatcher extends ArgumentMatcher<Class<?>> {

    @Override
    public boolean matches(final Object argument) {
        // We always return true, because we want to acknowledge all class types
        return true;
    }

}

private Class<?> anyClass() {
    return Mockito.argThat(new AnyClassMatcher());
}

and then call

Mockito.when(mock.doIt(this.anyClass())).thenCallRealMethod();

Solution 3 - Java

Nice one @Ash. I used your generic class matcher to prepare below. This can be used if we want to prepare mock of a specific Type.(not instance)

private Class<StreamSource> streamSourceClass() {
    return Mockito.argThat(new ArgumentMatcher<Class<StreamSource>>() {

		@Override
		public boolean matches(Object argument) {
			// TODO Auto-generated method stub
			return false;
		}
	});
}

Usage:

	Mockito.when(restTemplate.getForObject(Mockito.anyString(), 
			**streamSourceClass(),**
			Mockito.anyObject));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter Perh&#225;čView Question on Stackoverflow
Solution 1 - JavaJesseView Answer on Stackoverflow
Solution 2 - JavaAshView Answer on Stackoverflow
Solution 3 - Javauser3777313View Answer on Stackoverflow