首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模拟混凝土类

模拟混凝土类
EN

Stack Overflow用户
提问于 2013-01-17 08:07:13
回答 3查看 24.3K关注 0票数 9

考虑到以下代码:

代码语言:javascript
复制
    LinkedList list = mock(LinkedList.class);
    doCallRealMethod().when(list).clear();
    list.clear();

通过执行此测试,将从NullPointerException中的第一行抛出一个LinkedList#clear:

代码语言:javascript
复制
public void clear() {
    Entry<E> e = header.next;
    while (e != header) {
        Entry<E> next = e.next;
        //Code omitted. 

但是,以前已经被实例化过:

代码语言:javascript
复制
private transient Entry<E> header = new Entry<E>(null, null, null);

有人能解释一下在模拟创作过程中发生了什么吗?

#######更新######

在阅读了所有答案(尤其是Ajay的答案)之后,我查看了Objenesis源代码,发现它正在使用反射API创建代理实例(通过CGLIB),因此绕过了层次结构中的所有构造函数直到java.lang.Object。

下面是模拟问题的示例代码:

代码语言:javascript
复制
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;
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-17 08:40:30

你的推理完美无缺。

关键问题是,您没有对实际的LinkedList对象进行操作。下面是幕后发生的事情:

Mockito的mock()给出的对象是CGLIB库中的增强剂对象。

对我来说,这有点像java.util.LinkedList$$EnhancerByMockitoWithCGLIB$$cae81a28

哪种行为类似于代理,尽管字段设置为默认值。(null,0等)

票数 7
EN

Stack Overflow用户

发布于 2013-01-17 08:10:39

你只要求Mockito把真实的东西说清楚,底层的对象仍然是由Mockito为您创建的假对象。如果您需要一个真正的LinkedList,那么只需使用LinkedList -只有最热的纯粹的BDD会告诉您嘲笑周围的一切。我是说,你不是在嘲笑弦乐吧?

Mockito作者本人曾说过,调用真正的代码应该很少使用,通常只用于测试遗留代码。

如果您需要监视真实的对象(跟踪调用),那么Mockito也有这样的特性:

代码语言:javascript
复制
List list = new LinkedList();
List spy = spy(list);

有了间谍,如果你需要的话,你仍然可以对一个方法进行存根。它基本上像一个模拟,但不是;)

票数 9
EN

Stack Overflow用户

发布于 2013-01-17 08:13:03

当您模拟一个类时,您使用的对象是假的,因此变量不是实例化的,方法也不能像预期的那样工作。您可以使用反射来设置标题的值,但我真的不推荐这样做。正如theadam所说,最好的办法就是用一张单子。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14374584

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档