In Java I want to write test for method (simplified snippet):
public class MyClass {
private static final Set<Class> SOME_SET = new HashSet<Class>(Arrays.asList(Foo.class, Bar.class));
public boolean isValid(Class clazz){
return SOME_SET.contains(clazz);
}
}
The problem with following test
import static org.mockito.Mockito.when;
import org.mockito.Mockito;
public class MyClassTest {
@Test
public void isValid_Foo_returnsTrue(){
Foo foo = Mockito.mock(Foo.class);
MyClass target = new MyClass();
assertTrue(target.isValid(foo));
}
}
is that on mocked class Foo, foo.getClass()
returns the class name with additional suffix. Something like this:
Foo$$EnhancerByMockitoWithCGLIB$$45508b12
Because of this reason test fails because SOME_SET.contains(clazz) returns false.
I was unable to mock getClass() method on Foo:
Mockito.when(foo.getClass()).thenReturn(Foo.class);
Because compiler was complaining: The method thenReturn(Class<capture#1-of ? extends Foo>) in the type OngoingStubbing<Class<capture#1-of ? extends Foo>> is not applicable for the arguments (Class<Foo>)
The question is, how to achieve that getClass() method of mocked object returns same value as getClass() method on real(non mocked) object?
getClass() method returns the runtime class of an object. That Class object is the object that is locked by static synchronized methods of the represented class.
The Java Object getClass() method returns the class name of the object.
Configure Mockito for Final Methods and Classes Before we can use Mockito for mocking final classes and methods, we have to configure it. Mockito checks the extensions directory for configuration files when it is loaded. This file enables the mocking of final methods and classes.
Mockito.mock(Foo.class) results a object in type of Foo, but not exactly Foo class. As at the background it will create an anonymous proxy, which is a subclass of Foo. So, the class isn't the same.
One note to your implementation of isValid is that: do you really want to check the class, or just to check the type (that will also accept subclass, isAssignableFrom) of the class. If you check for type matching, then you can test your method with mocked class.
Also, do you think that you can somehow work on objects rather than classes (e.g. isValid(object))? Using object is a better approach in OOP than clazz in my perspective. I would suggest:
public boolean isValid(Object obj) {
return SOME_SET.stream().anyMatch(clazz -> clazz.isInstance(obj));
}
I see no sense on mocking Foo on your scenario. Just pass Foo.class as param. You are checking MyClass.isValid logic, and you are not gonna check any interaction on Foo.
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