测试失败时记录异常的最佳方法(例如使用junit规则) [英] Best way of logging exceptions when tests fail (e.g. using a junit rule)

查看:438
本文介绍了测试失败时记录异常的最佳方法(例如使用junit规则)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我运行完整的测试套件时,如果导致测试失败的异常会出现在我的(SLF4J-)日志中,这将是有帮助的。实现这一点的最好方法是什么?

When I'm running a complete test suite, it would be helpful if exceptions that caused a test to fail would appear in my (SLF4J-)log. What is the best method to achieve this?

是一个处理异常的junit4规则为我记录代码

is a junit4 rule that handles exception logging for me. The code

@Rule
public TestRule logException = new TestWatcher() {
    @Override
    public void failed(Description d) {
        catch (Exception e) {
            logger.error("Test ({}) failed because of exception {}", d, e);
            throw e;
        }
    }
}

当然不行,因为我只能从try块中捕获异常。有没有解决方法以某种方式以类似的简单和一般的方式实现这一点?

of course does not work, since I can only catch exceptions out of a try block. Is there a workaround to somehow achieve this in a similarly simple and general way?

在创建时记录异常。但是在调用者和库之间的接口上记录异常会更好一些,所以在我的情况下在测试用例中。创建异常时不记录也会保证当呼叫方决定登录时不会多次显示异常。

is logging the exception the moment it is created. But it would be nicer to log exceptions at the interface between caller and the library, so in my case in the test case. Not logging when the exceptions are created would also guarantee that they don't show up multiple times when the caller decides to log them.

推荐答案

您需要扩展TestRule,特别是apply()。举个例子,看看org.junit.rules.ExternalResource& org.junit.rules.TemporaryFolder。

You need to extend TestRule, in particular the apply(). For an example, have a look at org.junit.rules.ExternalResource & org.junit.rules.TemporaryFolder.

ExternalResource如下所示:

ExternalResource looks like this:

public abstract class ExternalResource implements TestRule {
    public Statement apply(Statement base, Description description) {
        return statement(base);
    }

    private Statement statement(final Statement base) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                before();
                try {
                    base.evaluate();
                } finally {
                    after();
                }
            }
        };
    }

    /**
     * Override to set up your specific external resource.
     * @throws if setup fails (which will disable {@code after}
     */
    protected void before() throws Throwable {
        // do nothing
    }

    /**
     * Override to tear down your specific external resource.
     */
    protected void after() {
        // do nothing
    }
}

TemporaryFolder然后扩展它并实现before()和after( )

TemporaryFolder then extends this and implements before() and after().

public class TemporaryFolder extends ExternalResource {
    private File folder;

    @Override
    protected void before() throws Throwable {
        // create the folder
    }

    @Override
    protected void after() {
        // delete the folder
    }

所以以前在testMethod之前被调用,之后被调用在最后,但你可以捕获并记录任何异常,如:

So the before gets called before the testMethod, and the after is called in the finally, but you can catch and log any Exception, like:

    private Statement statement(final Statement base) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                before();
                try {
                    base.evaluate();
                } catch (Exception e) {
                    log.error("caught Exception", e);
                } finally {
                    after();
                }
            }
        };
    }

编辑:以下作品:

public class SoTest {
    public class ExceptionLoggingRule implements TestRule {
        public Statement apply(Statement base, Description description) {
            return statement(base);
        }

        private Statement statement(final Statement base) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        base.evaluate();
                    } catch (Exception e) {
                        System.out.println("caught an exception");
                        e.printStackTrace(System.out);
                        throw e;
                    }
                }
            };
        }
    }

    @Rule public ExceptionLoggingRule exceptionLoggingRule = new ExceptionLoggingRule();
    @Rule public ExpectedException expectedException = ExpectedException.none();

    @Test
    public void testMe() throws Exception {
        expectedException.expect(IOException.class);
        throw new IOException("here we are");
    }
}

测试通过,您将获得以下输出: / p>

The test passes and you get the following output:

caught an exception
java.io.IOException: here we are
    at uk.co.farwell.junit.SoTest.testMe(SoTest.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
...

应用规则的顺序是ExpectedException,它调用调用testMe方法的ExceptionLoggingRule 。 ExceptionLoggingRule捕获异常,记录它并重新抛出它,然后由ExpectedException处理。

The order that the rules are applied is ExpectedException which calls ExceptionLoggingRule which calls the testMe method. The ExceptionLoggingRule catches the Exception, logs it and rethrows it, and it is then processed by ExpectedException.

如果只想记录意外的异常,只需切换声明顺序的规则:

If you want to log only unexpected exceptions, you just switch the declaration order of the rules:

    @Rule public ExpectedException expectedException = ExpectedException.none();
    @Rule public ExceptionLoggingRule exceptionLoggingRule = new ExceptionLoggingRule();

这样一来,expectedException首先被应用(即嵌套在exceptionLoggingRule中),只能重新抛出异常预期。此外,如果有一些异常被预期并且没有发生,则expectedException将抛出一个也将被记录的AssertionError。

That way, expectedException is applied first (i.e. nested in exceptionLoggingRule), and only rethrows exceptions that are not expected. Furthermore, if some exception was expected and none occured, expectedException will throw an AssertionError which will also get logged.

此评估订单不能保证,但除非您使用非常不同的JVM,或在Test类之间继承,否则不大可能改变。

This evaluation order isn't guaranteed, but it is quite unlikely to vary unless you're playing with very different JVMs, or inheriting between Test classes.

如果评估顺序很重要,那么您可以随时将一个规则传递给另一个规则进行评估。

If the evaluation order is important, then you can always pass one rule to the other for evaluation.

编辑:最近发布的Junit 4.10,您可以使用@RuleChain正确链接规则:

With the recently released Junit 4.10, you can use @RuleChain to chain rules correctly:

public static class UseRuleChain {
   @Rule
   public TestRule chain= RuleChain
                          .outerRule(new LoggingRule("outer rule")
                          .around(new LoggingRule("middle rule")
                          .around(new LoggingRule("inner rule");

   @Test
   public void example() {
           assertTrue(true);
   }
}

写日志

starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule

这篇关于测试失败时记录异常的最佳方法(例如使用junit规则)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆