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

Mockito spy failed because class member cannot be initialised

我有以下代码:

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。这个静态 class 的原因是初始化更多其他 class 对象,这些对象在测试期间不可用(例如数据库),我不在乎,因为你可以看到我可以 return null当方法 getMyObject() 被调用时。

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

上述情况的解决方法是使用 mock(MyClass.class) 而不是 spy(new MyClass()),这样私有成员 myObject 就不会被初始化,因此不会调用真正的 getMyObject()方法。

但是这个解决方法让我感到另一个头疼,因为这意味着我将不得不为 MyClass.

中的那些堆更多方法做一些配置(甚至只是 doCallRealMethod()

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

P.S。我不能简单地使用 Power Mock 来模拟 MyStaticClass,因为我已经在使用另一个测试 运行ner 来模拟 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));
    }
}

创建 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
  }

}

一般来说,这是一个潜在的问题原因,因为您在构造函数中调用了非私有、非最终方法。对于测试用例,它可能是可以接受的。

稍稍退后一步,我想看看这个 MyClass 对象的职责是明智的。是不是做的太多了,不好测试,不好交互?这通常会导致 "hard-to-mock" 综合症。