我对Mockito没有太多经验 - 我发现了一些我无法解释的行为:我有一个简单的类,让我们这样说
public class Testee {
protected MyParam myParam;
public void myMethod(){
myParam = new MyParam();
myParam.someField = "a new value";
}
此类中变量myParam
的类型是一个只有一个公共字段的类:
public class MyParam {
public String someField;
}
现在我想为Testee
类编写一个测试,我这样做是这样的:
@RunWith(PowerMockRunner.class)
public class TestTestee {
@InjectMocks
Testee testee = new Testee();
@Mock
MyParam myParam;
@Test
public void testMyMethod(){
myParam.someField = "old value";
testee.myMethod();
assertEquals("a new value", myParam.someField);
}
}
但是这个测试失败了!结果消息为:
org.junit.ComparisonFailure:
Expected: a new value
Actual: old value
因此,模拟实际上是正确注入的,但它似乎没有注意到,真实类中的方法将新值写入模拟变量 (myParam = new MyParam();
)。模拟的值保持不变 - 测试失败。这让我有点困惑,尤其是关于如果我简单地删除行myParam = new MyParam();
,那么测试就会成功!
因此,模拟无法注意到将新对象写入模拟变量,但它确实注意到对对象所做的更改 - 我是否正确理解它?在这种情况下,测试myMethod()
写入myParam
的值的正确方法是什么?
发生这种情况是因为在Testee
wheremyParam = new MyParam()
的行上,对类成员Testee testee
的引用被重新分配给new MyParam()
。测试中的模拟对象尚未重新分配,仍指向原始值。
要解决此问题,您可以将 settersetSomeField(String someField)
添加到MyParam
中,而不是重新分配值,而是在Testee
中调用myParam.setSomeField("a new value")
。
因此,模拟无法注意到新对象被写入 模拟变量,但它确实注意到对对象所做的更改 - 我是否 理解正确吗?
这完全是关于引用指向内存中的哪个对象。在测试中,我们创建一个模拟,模拟框架将类成员设置为模拟的对象引用。
然后我们重新分配类成员,但我们的单元测试会检查模拟。模拟的对象引用尚未更改。
似乎您在这里并不需要模拟,因为您想传递具有特定状态的对象。您可能会重新考虑并简单地使用二传手。
如果你真的必须并且可能需要模拟该类的一些公共方法,那么请尝试使用间谍而不是模拟:
@Spy
MyParam myParam;
现在默认情况下,将调用所有真正的实现,并且您需要显式模拟要存根的某些方法。