我正在使用 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来测试解决它,但是当@BeforeClass中的测试失败时,它会在运行规则之前运行@AfterClass。显然,就我而言,@AfterClass 删除了容器。
知道如何解决这个问题吗?
最佳答案
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
> 这也只是将调用传播到下一个规则 InitializationRule
。如果此规则失败,则由于缺少异常处理程序,该异常将传播到前任规则 CopyLosOnTestFailure
,异常处理程序将在其中启动并将日志复制到其他位置。由于异常被重新抛出,异常现在由第一条规则 CleanUpRule
处理,该规则仅执行 finally block ,因此执行之前的 @AfterClass
清理。
关于java - @BeforeClass失败时如何执行自定义代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38358964/