11

I'm trying to test an abstract class and Mockito does not initialize my member variables. Here's a simple example to show you my problem.

This is an abstract class that initializes its 'field' member:

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();
}

Here the test class:

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"));
    }
}

When the test is run it throws a NPE because the variable 'field' is not initialized!

What am I doing wrong?

4

2 回答 2

6

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

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

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

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

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

于 2013-07-30T15:17:19.417 回答
4

您似乎在嘲笑您实际尝试测试的课程。这不是嘲笑的真正想法。你模拟了超出你的测试范围的类,并且不模拟你正在测试的东西。

在这种情况下,您可能应该只创建一个Foo带有虚拟实现的 ,someAbstractMethod并直接对其进行测试。据我所知,不需要任何嘲笑。

于 2013-07-30T21:32:16.463 回答