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

时间:2019-07-17 17:55:45

标签: java unit-testing junit mockito

我对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();,则测试成功!

因此,该模拟程序无法注意到正在将新对象写入到模拟变量中,但是它确实注意到对该对象所做的更改-我是否正确理解它?在这种情况下,测试由myParam写入myMethod()的值的正确方法是什么?

2 个答案:

答案 0 :(得分:0)

似乎您实际上并不需要模拟,因为您希望传递具有特定状态的对象。您可能会重新考虑并只使用二传手。

如果您真的必须并且可能需要模拟该类的某些公共方法,则尝试使用间谍代替模拟:

@Spy
MyParam myParam;

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

答案 1 :(得分:0)

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

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

  

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

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

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