我使用junit与docker运行一些集成测试。
我有一个自定义的TestRule,可以在某个测试失败时从容器中复制日志:
public static class CopyLogsOnTestFailure implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return statement(base, description);
}
private Statement statement(final Statement base, Description description) {
return new Statement() {
final String pathToFolder = "/tmp/logs";
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Throwable caughtThrowable) {
logger.error("Copyings logs on failure!");
copyLogs(pathToFolder);
throw caughtThrowable;
}
}
};
}
现在,如果测试在@BeforeClass中失败,则不会复制日志,因为TestRule对@BeforeClass或@AfterClass方法没有好处。
我试图制作一个类似的@ClassRule来测试它,但是当@FeforeClass中的testfails运行时,它运行@AfterClass,然后运行规则。显然,在我的情况下,@ AfterClass删除容器。
知道如何解决这个问题吗?
答案 0 :(得分:2)
JUnit将执行代码的一般顺序如下(blog post with sample code):
@ClassRule
@BeforeClass
@Rule
@Before
@Test
method1()
@After
@Before
@Test2
method2()
@After
terminate rule
@AfterClass`
terminate class rule
我已经对执行进行了修改,因此如果在什么级别上引发异常,您可以更轻松地查看将执行哪些清理代码。
在第一个使用简单JUnit @Rule
带注释规则的情况下,异常发生在规则执行之前,这解释了@AfterClass
代码的执行。
在第二种情况下,首先执行@ClassRule
代码,然后执行@BeforeClass
中产生异常的代码。 Junit现在将尝试执行已执行方法的清理代码。首先执行@AfterClass
,然后执行@ClassRule
清理。
您可以将@BeforeClass
和@AfterClass
重构为另一个规则和chain them together with the other rule,但您可能会注意到相同的行为,因为外部规则在内部规则之前执行,如果内部失败,执行内部规则的清理,然后清除外部规则。如果外部规则失败,则内部规则根本不执行。
基本上你想要的是,如果我理解你的意图正确,就是为@AfterClass
清理创建一个外部规则,它正在做这样的清理工作:
public class CleanUpRule implements TestRule {
@Override
public Statement apply(final Statement base, final Description description) {
try {
base.evaluate();
} finally {
// @AfterClass cleanup code here
}
}
}
@BeforeClass
的代码可以放入其他规则
public class InitializationRule implements TestRule {
@Override
public Statement apply(final Statement base, final Description description) {
// @BeforeClass logic here
base.evaluate();
}
}
然后创建一个像这样的链规则:
@ClassRule
public static TestRule chain = RuleChain.outer(new CleanUpRule())
.around(new CopyLogsOnTestFailure())
.around(new InitializationRule());
JUnit将首先调用外部规则(CleanUpRule
)并调用base.evaluate()
方法,该方法将调用下一个规则CopyLogsOnTestFailure
,该规则也只是将调用传播到下一个规则{ {1}}。如果此规则失败,则由于缺少异常处理程序,异常将传播到先前规则InitializationRule
,异常处理程序将在该规则中启动并将日志复制到其他位置。当重新抛出异常时,异常现在由第一个规则CopyLosOnTestFailure
处理,它只执行finally块,因此执行前CleanUpRule
清理。