模拟getClass()

时间:2017-07-31 07:15:51

标签: java unit-testing junit mocking mockito

在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()方法相同的值

5 个答案:

答案 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将按预期工作。