简而言之,不知何故,mockito 间谍对象与原始对象混淆了。
这是类定义(伪代码)
public class MyClass {
private String m_name = "origin name";
private final Dumper m_dumper = new Dumper();
public void setName(String name) {
m_name = name;
}
public void print() {
m_dumper.print();
}
public void dumpName() {
System.out.println(m_name);
}
private class Dumper {
public void print() {
dumpName();
}
}
}
因此,如果我们创建对象并监视它:
MyClass originObject = new MyClass();
MyClass spyObject = Mockito.spy(originObject);
spyObject.setName("mock name");
spyObject.print(); //Here we are expecting it prints out "mock name" but actually "origin name"
我认为根本原因是,当我们监视原始对象时,监视对象有自己的成员“m_dumper”,但它仍然引用原始对象。
Mockito 创建一个新实例并复制原始实例的所有引用。由于
Dumper
是一个非静态嵌套类,因此它绑定到封闭类的实例。
所以基本上你有以下参考链:
spyObject -> spyObject.m_dumper -> spyObject.m_dumper.outerClass -> originObject
换句话说,
m_dumper
实例在spyObject
和originObject
之间共享。两个实例的字段包含相同的值并引用唯一的转储器实例。您可以使用调试器或通过打印字段引用的身份哈希代码轻松进行验证。
直接来自文档:
Mockito 不会将调用委托给传递的真实实例,而是实际上创建它的副本。因此,如果您保留真实实例并与其交互,则不要指望间谍能够意识到这些交互及其对真实实例状态的影响。推论是,当在间谍上但不在真实实例上调用未存根方法时,您不会看到对真实实例有任何影响。
您将保留真实实例并与其交互(通过非静态嵌套类
Dumper
,它保留对真实实例的引用)。