考虑到以下代码:
LinkedList list = mock(LinkedList.class);
doCallRealMethod().when(list).clear();
list.clear();通过执行此测试,将从NullPointerException中的第一行抛出一个LinkedList#clear:
public void clear() {
Entry<E> e = header.next;
while (e != header) {
Entry<E> next = e.next;
//Code omitted. 但是,头以前已经被实例化过:
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;
}
}发布于 2013-01-17 08:40:30
你的推理完美无缺。
关键问题是,您没有对实际的LinkedList对象进行操作。下面是幕后发生的事情:
Mockito的mock()给出的对象是CGLIB库中的增强剂对象。
对我来说,这有点像java.util.LinkedList$$EnhancerByMockitoWithCGLIB$$cae81a28
哪种行为类似于代理,尽管字段设置为默认值。(null,0等)
发布于 2013-01-17 08:10:39
你只要求Mockito把真实的东西说清楚,底层的对象仍然是由Mockito为您创建的假对象。如果您需要一个真正的LinkedList,那么只需使用LinkedList -只有最热的纯粹的BDD会告诉您嘲笑周围的一切。我是说,你不是在嘲笑弦乐吧?
Mockito作者本人曾说过,调用真正的代码应该很少使用,通常只用于测试遗留代码。
如果您需要监视真实的对象(跟踪调用),那么Mockito也有这样的特性:
List list = new LinkedList();
List spy = spy(list);有了间谍,如果你需要的话,你仍然可以对一个方法进行存根。它基本上像一个模拟,但不是;)
发布于 2013-01-17 08:13:03
当您模拟一个类时,您使用的对象是假的,因此变量不是实例化的,方法也不能像预期的那样工作。您可以使用反射来设置标题的值,但我真的不推荐这样做。正如theadam所说,最好的办法就是用一张单子。
https://stackoverflow.com/questions/14374584
复制相似问题