为什么Mockito跳过我的抽象类的成员变量的初始化

时间:2013-07-30 11:57:26

标签: java unit-testing abstract-class mockito

我试图测试一个抽象类,而Mockito没有初始化我的成员变量。这是一个向您展示我的问题的简单示例。

这是一个初始化其“'字段”的抽象类。构件:

import java.util.ArrayList;
import java.util.Collection;

public abstract class Foo {
    private final Collection field = new ArrayList();

    protected Foo() {
        System.out.println("In constructor");
    }

    public boolean isNull(Object o) {
        field.add(o);

        return o == null;
    }

    abstract void someAbstractMethod();
}

这里是测试类:

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class FooTest {
    @Test
    public void testSomething() {
        final Foo foo = Mockito.mock(Foo.class);

        Mockito.when(foo.isNull(Mockito.anyObject())).thenCallRealMethod();

        Assert.assertFalse(foo.isNull("baaba"));
    }
}

当测试运行时,它会抛出一个NPE,因为变量'字段'没有初始化!

我做错了什么?

2 个答案:

答案 0 :(得分:4)

这是预期的行为,当你模拟某个东西时,创建的实例是一个完整的模拟,所以初始化字段是没有意义的,因为行为是默认的

除此之外,字段可以由具体或抽象类中的构造函数初始化,因为模拟实例化仅仅因为它是模拟而绕过构造函数,初始化它们就更不合理了。

使用模拟时,尝试调用真实方法通常是错误的。相反,应该存在模拟行为。

Mockito.when(foo.isNull(Mockito.anyObject())).thenReturn(false);
Assert.assertFalse(foo.isNull("baaba")); // assertion always passing

我不知道你的实际用例,但也许你想要一个部分模拟,spy。虽然这仍然被认为是不好的做法,因为它通常意味着您需要重构代码以使用合成。

答案 1 :(得分:3)

你似乎在嘲笑你真正想要测试的课程。这并不是嘲笑的主意。您可以模拟超出测试范围的类,并保留您正在测试的东西。

在这种情况下,您可能只需创建Foo,使用someAbstractMethod的虚拟实现并直接测试。就我所见,无需任何嘲弄。