我有一个测试类,它正在测试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
之间的排序,我可以避免这个问题。或许还有一个我没想到的替代方案。
任何建议表示赞赏,谢谢!
答案 0 :(得分:2)
这不是@Rule
注释的问题,而是初始化测试类的成员变量。创建测试实例时,将初始化规则实例(resources
或testRule
)。即使没有附加@Rule
注释,也会发生这种情况(这是简单的java逻辑:当构造对象实例时,它的所有成员变量将在构造期间初始化)。
因此,当Mockito创建foo
模拟时,resources
或testRule
已经创建。如果您使用MockitoRule
,则此行为不会更改。
@Rule
注释只是告诉JUnit使用创建的对象作为规则,它不控制规则的创建。
所以我想唯一的解决方案确实是在测试初始化期间创建foo
模拟,即使用Foo foo = mock(Foo.class)