当前位置: 首页 > 面试题库 >

测试失败时记录异常的最佳方法(例如,使用junit规则)

卢普松
2023-03-14
问题内容

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

我想要什么

是为我处理异常日志记录的junit4规则。代码

@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块中捕获异常。是否有解决方法以某种类似的简单通用方法实现?

顺便说一句,我现在在做什么

在创建异常时记录异常。但是最好在调用者和库之间的接口上记录异常,所以在我的情况下是测试用例。在创建异常时不进行日志记录还可以保证在调用者决定对其进行记录时,它们不会多次出现。


问题答案:

您需要扩展TestRule,尤其是apply()。例如,查看org.junit.rules.ExternalResource和org.junit.rules.TemporaryFolder。

ExternalResource看起来像这样:

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()。

public class TemporaryFolder extends ExternalResource {
    private File folder;

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

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

因此,before在testMethod之前被调用,after在finally中被调用,但是您可以捕获并记录任何Exception,例如:

    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");
    }
}

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

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,它调用ExceptionLoggingRule,后者调用testMe方法。ExceptionLoggingRule捕获异常,将其记录并重新抛出,然后由ExpectedException处理。

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

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

这样,将首先应用ExpectedException(即嵌套在exceptionLoggingRule中),并且仅重新引发意外的异常。此外,如果预期某些异常但未发生任何异常,则ExpectedException将抛出一个AssertionError,该异常也会被记录。

不能保证此评估顺序,但是除非您使用的是非常不同的JVM,或在Test类之间继承,否则它几乎不可能改变。

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

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

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


 类似资料:
  • 我有一个简单的测试用例: FileManager中的函数删除 /myDir下的所有文件,然后再次保留文件。 如上所述,我有一个。运行时,我可以按以下顺序查看所有打印: 但是,测试在失败。有两件事我不明白: > 我不明白,它在中失败了,为什么我仍然可以看到打印的,听起来就像是失败了,它没有停止运行,而是继续运行下一个测试?JUnit测试用例中的场景背后发生了什么?? 我不明白的另一件事是为什么tes

  • 我正试图为一个方法编写一个测试用例,该方法基于特定的逻辑抛出异常。然而,测试用例失败了,因为预期的异常和获得的异常是不同的。 我如何解决这个问题?

  • 我正在使用JUnit和Apache Log4J来学习TDD和日志服务的最佳实践。我有一个类,它有一个方法,它将尝试连接到MySQL数据库并返回类型的对象。 我有一个类GenericTaskInterpreterTests,在这里我为这个方法(和其他方法)编写了测试用例。 在这个测试用例场景中,如何使用TestWatcher记录断言失败

  • 我正在使用一个Selenium/JUnit测试环境,我想实现一个类来执行“软断言”:这意味着我想让它记录断言是否通过,但在明确地告诉它验证断言之前,测试用例不会失败。这样,我可以检查页面上的多个字段,记录所有不匹配的字段。 我的“Verify”方法如下所示(/也存在类似的方法): 一旦验证了所有字段,我就调用以下方法: 目前,我只是使用来快速使测试用例失败;然而,这会使日志变得杂乱无章,导致一个无

  • 我有一个Spring应用程序 我插入的新代码-maven测试失败-但仅当我从intelliJ运行测试时才从maven测试成功。来自maven/jenkins失败 org . spring framework . beans . factory . beancreationexception:创建名为“predefinedModelHandlerService”的bean时出错:调用init方法失败

  • 我构建了一个有3个属性的帐户类:余额、所有者、acctNo。帐户类有2个构造函数,一个接受3个属性,一个不接受数据。帐户类有设置和获取方法以及存款和取款方法。 我还构建了一个类,该类从类扩展而来。将此类修改为类后,取款方法或此方法尝试将余额设置为零以下,将抛出。 JUnit测试人员修改测试方法,将尝试提取超过当前余额的可用,所以做测试方法。我需要修改JUnit测试透支帐户,以便它捕获异常,并捕获。