使用TestNG的自定义报告

2023/05/09

1. 概述

在本文中,我们将讨论使用TestNG生成自定义日志记录和报告。

TestNG提供了自己的报告功能-以HTML/XML格式生成报告。如果使用maven-surefire-plugin运行测试,则报告将采用插件定义的默认形式。除了内置报告外,它还提供了一种轻松自定义记录信息和生成报告的机制。

如果你想从TestNG基础开始,请查看这篇文章

2. 自定义日志

在我们实现自定义日志记录之前,让我们通过执行mvn test命令来查看默认日志:

Tests run: 11, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.21 sec <<< FAILURE! - in TestSuite whenCalledFromSuite_thanOK(cn.tuyucheng.taketoday.RegistrationTest)  
Time elapsed: 0.01 sec  <<< FAILURE!
java.lang.AssertionError: Test Failed due to some reason at cn.tuyucheng.taketoday.RegistrationTest.whenCalledFromSuite_thanOK(RegistrationTest.java:15)

Results :

Failed tests: RegistrationTest.whenCalledFromSuite_thanOK:15 Test Failed due to some reason

Tests run: 11, Failures: 1, Errors: 0, Skipped: 0

[ERROR] There are test failures.

这些日志不会为我们提供有关执行顺序或特定测试何时开始/完成等的任何信息。

如果我们想知道每次运行的结果以及一些自定义数据,我们可以实现自己的日志和报告。TestNG提供了一种实现自定义报告和日志记录的方法。

简单地说,我们可以实现用于日志记录的org.testng.ITestListener接口或用于报告的org.testng.IReporter接口。这些实现的类会收到有关测试和套件的开始、结束、失败等事件的通知。

让我们继续实现一些简单的自定义日志记录:

public class CustomisedListener implements ITestListener {

    // ...
    @Override
    public void onFinish(ITestContext testContext) {
        LOGGER.info("PASSED TEST CASES");
        testContext.getPassedTests().getAllResults().forEach(result -> {LOGGER.info(result.getName());});

        LOGGER.info("FAILED TEST CASES");
        testContext.getFailedTests().getAllResults().forEach(result -> {LOGGER.info(result.getName());});

        LOGGER.info("Test completed on: " + testContext.getEndDate().toString());
    }

    // ...
}

请注意我们是如何覆盖onFinish()方法的,该方法将在所有测试执行完成且所有配置完成时被调用。同样,我们可以覆盖其他方法-例如onTestStart()、onTestFailure()等(此处可以找到有关这些其他方法的详细信息)。

现在,让我们将这个监听器包含在XML配置中:

<suite name="My test suite">
    <listeners>
        <listener class-name="cn.tuyucheng.taketoday.reports.CustomisedListener"/>
    </listeners>
    <test name="numbersXML">
        <parameter name="value" value="1"/>
        <parameter name="isEven" value="false"/>
        <classes>
            <class name="cn.tuyucheng.taketoday.ParametrizedTests"/>
        </classes>
    </test>
</suite>

一旦执行,监听器将在每个事件上被调用,并在我们的实现中记录信息。这对于调试我们的测试执行可能很有用。

输出日志:

...
INFO CUSTOM_LOGS - Started testing on: Sat Apr 22 14:39:43 IST 2017
INFO CUSTOM_LOGS - Testing: givenNumberFromDataProvider_ifEvenCheckOK_thenCorrect
INFO CUSTOM_LOGS - Tested: givenNumberFromDataProvider_ifEvenCheckOK_thenCorrect Time taken:6 ms
INFO CUSTOM_LOGS - Testing: givenNumberObjectFromDataProvider_ifEvenCheckOK_thenCorrect
INFO CUSTOM_LOGS - Failed : givenNumberObjectFromDataProvider_ifEvenCheckOK_thenCorrect
INFO CUSTOM_LOGS - PASSED TEST CASES
INFO CUSTOM_LOGS - givenNumberFromDataProvider_ifEvenCheckOK_thenCorrect
INFO CUSTOM_LOGS - FAILED TEST CASES
INFO CUSTOM_LOGS - givenNumberObjectFromDataProvider_ifEvenCheckOK_thenCorrect
INFO CUSTOM_LOGS - Test completed on: Sat Apr 22 14:39:43 IST 2017
...

自定义日志为我们提供了默认日志中缺少的信息。

3. 自定义报告

当我们使用插件运行测试时,它会在target/surefire-reports目录中生成HTML/XML格式的报告:

如果我们想使用TestNG XML文件运行一个特定的测试套件,我们需要在surefire插件的configuration标签中列出它:

<configuration>
    <suiteXmlFiles>
        <suiteXmlFile>
            src\test\resources\parametrized_testng.xml
        </suiteXmlFile>
    </suiteXmlFiles>
</configuration>

在自定义日志记录之后,现在让我们尝试创建一些自定义报告,我们在其中实现org.testng.IReporter接口并覆盖generateReport()方法:

public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
    String reportTemplate = initReportTemplate();

    String body = suites
        .stream()
        .flatMap(suiteToResults())
        .collect(Collectors.joining());

    String report = reportTemplate.replaceFirst("</tbody>", String.format("%s</tbody>", body));
    saveReportTemplate(outputDirectory, report);
}

被重写的方法接收三个参数:

  • xmlSuite:包含XML文件中提到的所有套件的列表
  • suites:一个列表对象,包含有关测试执行的所有信息
  • outputDirectory:生成报告的目录路径

我们使用initReportTemplate()方法加载一个HTML模板,suiteToResults()函数调用resultsToRow()函数来处理生成报告的内部机制:

private Function<ISuite, Stream<? extends String>> suiteToResults() {
    return suite -> suite.getResults().entrySet()
        .stream()
        .flatMap(resultsToRows(suite));
}

private Function<Map.Entry<String, ISuiteResult>, Stream<? extends String>> resultsToRows(ISuite suite) {
    return e -> {
        ITestContext testContext = e.getValue().getTestContext();

        Set<ITestResult> failedTests = testContext.getFailedTests().getAllResults();
        Set<ITestResult> passedTests = testContext.getPassedTests().getAllResults();
        Set<ITestResult> skippedTests = testContext.getSkippedTests().getAllResults();

        String suiteName = suite.getName();

        return Stream
            .of(failedTests, passedTests, skippedTests)
            .flatMap(results -> generateReportRows(e.getKey(), suiteName, results).stream());
    };
}

saveReportTemplate()用于保存完整的结果。

在XML配置文件中包含报告器:

<suite name="suite">
    <listeners>
        <listener class-name="cn.tuyucheng.taketoday.reports.CustomisedReports"/>
    </listeners>
    <test name="test suite">
        <classes>
            <class name="cn.tuyucheng.taketoday.RegistrationTest"/>
            <class name="cn.tuyucheng.taketoday.SignInTest"/>
        </classes>
    </test>
</suite>

这是我们报告的输出:

与默认的surefire HTML报告相比,此报告在单个表格中提供了清晰明了的结果图片。哪个更方便,更易于阅读。

4. 总结

在这个快速教程中,我们学习了如何使用Surefire Maven插件生成测试报告。我们还研究了使用TestNG自定义日志和生成自定义报告。有关TestNG的更多详细信息,例如如何编写测试用例、套件,请务必从我们的介绍性文章开始。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章