在Java中我想编写方法测试(简化代码段):
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);
}
}
以下测试的问题
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));
}
}
是在模拟类Foo上,foo.getClass()
返回带有附加后缀的类名。像这样:
Foo$$EnhancerByMockitoWithCGLIB$$45508b12
由于这个原因,测试失败,因为 SOME_SET.contains(clazz)返回 false 。
我无法在Foo上模拟 getClass()方法:
Mockito.when(foo.getClass()).thenReturn(Foo.class);
因为编译器抱怨: 然后返回类型OngoingStubbing&lt; Class&lt; capture#1-of?扩展Foo&gt;&gt;不适用于参数(Class&lt; Foo&gt;)
问题是,如何实现模拟对象的getClass()方法在真实(非模拟)对象上返回与getClass()方法相同的值?
答案 0 :(得分:4)
Mockito.mock(Foo.class)在Foo类型中生成一个对象,但不完全是Foo类。在后台,它将创建一个匿名代理,它是Foo的子类。所以,班级不一样。
对isValid实现的一个注意事项是:你真的要检查类,还是只检查类的类型(也将接受子类isAssignableFrom)。如果检查类型匹配,那么可以使用模拟类测试方法。
另外,你认为你可以以某种方式处理对象而不是类(例如isValid(object))吗?在我看来,使用对象是OOP中比clazz更好的方法。 我建议:
public boolean isValid(Object obj) {
return SOME_SET.stream().anyMatch(clazz -> clazz.isInstance(obj));
}
答案 1 :(得分:2)
我觉得在你的场景中模仿Foo没有任何意义。只需将Foo.class作为参数传递即可。您正在检查MyClass.isValid逻辑,并且您不会检查Foo上的任何交互。
答案 2 :(得分:1)
简单:你不能。
请记住:模拟对象实际上不是模拟类。模拟框架为您创建 但是你不能两种方式:伪造或者真实。
在你的情况下,合理的测试无论如何看起来都不同:
@Test
public void testIsValidForInvalidClass() {
assertThat(target.isValid(String.class), is(false));
}
@Test
public void testIsValidForValidClass() {
assertThat(target.isValid(Foo.class), is(true));
}
例如,。首先嘲笑 Class 对象是没有意义的。您可以轻松构建并传递类Class的真实对象!
答案 3 :(得分:0)
初始化对象'foo'时,只需创建一个Foo类型的对象,而不是创建一个Foo模拟。例如,如果可能:
Foo foo = new Foo()
答案 4 :(得分:0)
这可以通过当前正在孵化的替代模拟制作器实现来实现。请参见here如何启用它。
在此类模拟上调用getClass
会返回原始类,因此equals
将按预期工作。