首页 文章

当@BeforeClass失败时,如何执行自定义代码

提问于
浏览
0

我正在使用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删除容器 .

知道如何解决这个问题吗?

1 回答

  • 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 ,该规则也只是将调用传播到下一个规则 InitializationRule . 如果此规则失败,则由于缺少异常处理程序,异常将传播到先前规则 CopyLosOnTestFailure ,异常处理程序将在该规则中启动并将日志复制到其他位置 . 当异常被重新抛出时,异常现在由第一个规则 CleanUpRule 处理,该规则只执行finally块,因此执行前 @AfterClass 清理 .

相关问题