java - @BeforeClass失败时如何执行自定义代码

标签 java junit

我正在使用 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/

相关文章:

groovy - JBehave - 所有步骤都标记为待处理?

java - 在 JUnit 的 setUp() 中初始化对象数组

java - Junit EasyMock, resultSet.getBigDecimal ("") 返回空值

hadoop - 如何运行 MRUnit?

java - Class 和 Class<?> 之间的真正区别(如果有的话)是什么?

java - 如何使用 Spring self 描述 REST api?

java - 在android中创建一个webm文件

java - 如何获取图像(在文件中)的 channel 数(颜色深度)?

java - 将文件从服务器上传到另一台服务器的 Hdfs

java - 如何仅通过使用 TestWatcher 来判断 JUnit 何时完成?