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

Initialize mocks via @Mock before @Rule

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

Foo foo = mock(Foo.class);

这有点冗长

@Mock Foo foo;

但是 Dropwizard ResourceTestRule 需要像这样引用这些模拟

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

我的问题是 @Mock 之前的 @Rule 运行 初始化模拟,因此 BarResource 实例化时 foo 为空,并且然后我在测试 运行.

时得到空指针异常

这是一个没有使用 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 之间的顺序,我就可以避免这个问题。或者也许还有其他我没有想到的选择。

感谢任何建议,谢谢!

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

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

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