Java,Mockito:通过@InjectMocks模拟的字段不会注意到写入真实变量的新值



我对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的值的正确方法是什么?

发生这种情况是因为在TesteewheremyParam = new MyParam()的行上,对类成员Testee testee的引用被重新分配给new MyParam()。测试中的模拟对象尚未重新分配,仍指向原始值。

要解决此问题,您可以将 settersetSomeField(String someField)添加到MyParam中,而不是重新分配值,而是在Testee中调用myParam.setSomeField("a new value")

因此,模拟无法注意到新对象被写入 模拟变量,但它确实注意到对对象所做的更改 - 我是否 理解正确吗?

这完全是关于引用指向内存中的哪个对象。在测试中,我们创建一个模拟,模拟框架将类成员设置为模拟的对象引用。

然后我们重新分配类成员,但我们的单元测试会检查模拟。模拟的对象引用尚未更改。

似乎您在这里并不需要模拟,因为您想传递具有特定状态的对象。您可能会重新考虑并简单地使用二传手。

如果你真的必须并且可能需要模拟该类的一些公共方法,那么请尝试使用间谍而不是模拟:

@Spy
MyParam myParam;

现在默认情况下,将调用所有真正的实现,并且您需要显式模拟要存根的某些方法。

相关内容

  • 没有找到相关文章

最新更新