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" 综合症。
我有以下代码:
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" 综合症。