给定以下代码:
LinkedList list = mock(LinkedList.class);
doCallRealMethod().when(list).clear();
list.clear();
通过执行此测试,从 LinkedList#clear 的第一行抛出 NullPointerException:
public void clear() {
Entry<E> e = header.next;
while (e != header) {
Entry<E> next = e.next;
//Code omitted.
但是header之前已经实例化过:
private transient Entry<E> header = new Entry<E>(null, null, null);
有人可以解释一下模拟创建过程中发生了什么吗?
####### 更新。 ######
阅读了所有答案,尤其是 Ajay 的答案后,我查看了 Objenesis 源代码,发现它使用反射 API 创建代理实例(通过 CGLIB),因此绕过了层次结构中的所有构造函数,直到 java.lang.Object。
下面是模拟问题的示例代码:
public class ReflectionConstructorTest {
@Test
public void testAgain() {
try {
//java.lang.Object default constructor
Constructor javaLangObjectConstructor = Object.class
.getConstructor((Class[]) null);
Constructor mungedConstructor = ReflectionFactory
.getReflectionFactory()
.newConstructorForSerialization(CustomClient.class, javaLangObjectConstructor);
mungedConstructor.setAccessible(true);
//Creates new client instance without calling its constructor
//Thus "name" is not initialized.
Object client = mungedConstructor.newInstance((Object[]) null);
//this will print "CustomClient"
System.out.println(client.getClass());
//this will print "CustomClient: null". name is null.
System.out.println(client.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
}
class CustomClient {
private String name;
CustomClient() {
System.out.println(this.getClass().getSimpleName() + " - Constructor");
this.name = "My Name";
}
@Override
public String toString() {
return this.getClass().getSimpleName() + ": " + name;
}
}
最佳答案
你只是要求 Mockito 在 clear 上调用真实的东西,底层对象仍然是 Mockito 为你创建的假对象。如果您需要一个真正的 LinkedList,那么只需使用 LinkedList - 只有最激烈的 BDD 纯粹主义者才会告诉您模拟周围的一切。我的意思是,您不是在 mock Strings 吗?
Mockito 作者自己说过调用真实的东西应该很少使用,通常只用于测试遗留代码。
如果您需要监视真实对象(跟踪调用),那么 Mockito 也有一个功能:
List list = new LinkedList();
List spy = spy(list);
有了 spy ,如果需要,您仍然可以对方法进行 stub 。它基本上像模拟一样工作,但不是 ;)
关于java - Mockito - 模拟具体类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14374584/