Mockito间谍失败,因为班级成员无法初始化

时间:2017-10-04 01:41:25

标签: java mocking mockito powermock powermockito

我有以下代码:

public class MyClass() {
    private MyObject myObject = getMyObject();
    public MyObject getMyObject() {
        if (myObject == null) {
            myObject = MyStaticClass.createMyObject();
        }
        return myObject;
    }
    // heaps more methods
}

public class MyTest() {
    private MyClass spyMyClass = spy(new MyClass());
    public MyTest() {
        doReturn(null).when(spyMyClass).getMyObject();
    }
    @Test
    public void someTest() {
        ClassUnderTest c = new ClassUnderTest();
        assertTrue(c.someMethod(spyMyClass));
    }
}

测试失败,错误为Could not initialise class MyStaticClass。这个静态类的原因是初始化了许多在测试期间不可用的其他类对象(例如数据库),我不在乎你可以看到我可以在调用方法getMyObject()时返回null。 / p>

但是这个意图也失败了,因为在达到doReturn(null)行之前,测试已经在spy(new MyClass())行失败,在getMyObject()行调用myObject初始化私有成员{ {1}}。

针对上述情况的解决方法是使用mock(MyClass.class)而不是spy(new MyClass()),以便私有成员myObject未初始化,因此不会调用真实的getMyObject()方法

但是这种解决方法给我带来了另一个麻烦,因为这意味着我必须对doCallRealMethod()内的更多方法进行一些配置(即使只是MyClass)。

问题:还有另一个解决方案,我仍然可以在MyClass的实例上使用间谍,这样我就可以忘记在这个类中配置更多方法,但我可以绕过Could not initialise class MyStaticClass错误?

P.S。我不能简单地使用Power Mock来模拟MyStaticClass因为我已经在为MyTest使用另一个测试运行器了。除非你的回答能够说明在没有实现结合两者的新混合测试运行器的情况下同时运行两个测试运行器是多么容易。

感谢Adam,现在我有一个很好的工作代码:

public class MyTest() {
    private MyClass spyMyClass = spy(new MyClass() {
        @Override
        public MyObject getMyObject() {
            return null;
        }
    });
    @Test
    public void someTest() {
        ClassUnderTest c = new ClassUnderTest();
        assertTrue(c.someMethod(spyMyClass));
    }
}

1 个答案:

答案 0 :(得分:2)

创建MyClass的子类并在private MyClass spyMyClass = spy(new TestMyClass());中使用它:

class TestMyClass extends MyClass {

  @Override // fortunately, the original method called in constructor can be overridden (what could be considered bad)
  public MyObject getMyObject() {
    // something that does not fail the constructor
  }

}

通常,这是导致问题的潜在原因,因为您在构造函数中调用了非私有的非final方法。对于测试用例,这可能是可以接受的。

稍微走开一点,我想看看这个MyClass对象的职责是明智的。它不是做得太多,因此很难测试和互动吗?这通常导致难以模拟"综合征。