在@Rule之前通过@Mock初始化模拟

时间:2018-03-02 23:39:52

标签: java junit mockito dropwizard

我有一个测试类,它正在测试Dropwizard资源并使用JUnit测试规则ResourceTestRule。它设置了许多模拟,我想替换这个成语:

Foo foo = mock(Foo.class);

这个

有点冗长

@Mock Foo foo;

然而,Dropwizard ResourceTestRule需要像这样引用这些模拟

@Rule
public ResourceTestRule resources = ResourceTestRule.builder()
        .addResource(new BarResource(foo))
        .build();

我的问题是@Rule@Mock初始化模拟之前运行,因此当foo被实例化时BarResource为空,然后我得到空指针异常当我的测试运行时。

这是一个没有Dropwizard内容的最小例子来证明这个问题:

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class TestTest {
    @Mock String foo;

    @Rule
    public TestRule testRule = new TestRule() {
        {
            assert foo != null; // <<< this assertions fails
        }

        @Override
        public Statement apply(Statement statement, Description description) {
            return statement;
        }
    };

    @Test
    public void test() {

    }
}

如果我可以控制@Mock@Rule之间的排序,我可以避免这个问题。或许还有一个我没想到的替代方案。

任何建议表示赞赏,谢谢!

1 个答案:

答案 0 :(得分:2)

这不是@Rule注释的问题,而是初始化测试类的成员变量。创建测试实例时,将初始化规则实例(resourcestestRule)。即使没有附加@Rule注释,也会发生这种情况(这是简单的java逻辑:当构造对象实例时,它的所有成员变量将在构造期间初始化)。

因此,当Mockito创建foo模拟时,resourcestestRule已经创建。如果您使用MockitoRule,则此行为不会更改。 @Rule注释只是告诉JUnit使用创建的对象作为规则,它不控制规则的创建。

所以我想唯一的解决方案确实是在测试初始化​​期间创建foo模拟,即使用Foo foo = mock(Foo.class)