通过测试监听器删除(复制)失败的TestNG结果

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过测试监听器删除(复制)失败的TestNG结果相关的知识,希望对你有一定的参考价值。

类似于此处发布的解决方案TestNG retrying failed tests doesn't output the correct test results,我试图在onFinish(ITestContext上下文)中使用测试侦听器删除(重复)测试结果。

尽管使用context.getFailedTests()。removeResult(result)删除结果似乎工作正常(结果实际上已被删除),但似乎存在“某些其他位置”,其中结果被拉出,因为构建仍然失败。

还要注意,当我从上面的文章(其中有一个重复的失败被删除和一个通过测试)运行样本测试时,我得到了“测试结果”(没有按预期清理)与“套件结果”的区别(重复故障按预期删除)。

而且,报告从哪里提取结果以决定是否使构建失败?或者只是它在我清理失败的测试之前拉动结果......?

===============================================
    Default test
    Tests run: 3, Failures: 2, Skips: 0
===============================================

===============================================
Default suite
Total tests run: 2, Failures: 1, Skips: 0  
===============================================

编辑:只是为了澄清,我们正在使用maven运行这些测试,他们是IT,因此我们使用failsafe插件运行它们。问题是即使看起来测试被删除,mvn验证仍然无法构建,因为它认为无论如何都会发现构建失败。

而且如果从Eclipse运行这样的测试,即使删除了测试,当套件完成时,仍会在日志中打印失败。

关于RetryAnalyzer:我根本不会考虑使用RetryAnalyzer良好/最佳实践,但如果您发现自己处于需要解决问题的情况,例如你继承了一个依赖RetryAnalyzer的测试套件,你可能会觉得这很有用。

答案

尝试使用此代码:

ListenerApadter:

public class MyTestListenerAdapter extends TestListenerAdapter {
    @Override
    public void onTestFailure(ITestResult result) {
        if (result.getMethod().getRetryAnalyzer() != null) {
            MyRetryAnalyzer retryAnalyzer = (MyRetryAnalyzer)result.getMethod().getRetryAnalyzer();

            if(retryAnalyzer.isRetryAvailable()) {
                result.setStatus(ITestResult.SKIP);
            } else {
                result.setStatus(ITestResult.FAILURE);
            }
            Reporter.setCurrentTestResult(result);
        }
    }

   @Overrride
   public void onFinish(ITestContext context) {
     Iterator<ITestResult> failedTestCases =context.getFailedTests().getAllResults().iterator();
    while (failedTestCases.hasNext()) {
        System.out.println("failedTestCases");
        ITestResult failedTestCase = failedTestCases.next();
        ITestNGMethod method = failedTestCase.getMethod();
        if (context.getFailedTests().getResults(method).size() > 1) {
            System.out.println("failed test case remove as dup:" + failedTestCase.getTestClass().toString());
            failedTestCases.remove();
        } else {

            if (context.getPassedTests().getResults(method).size() > 0) {
                System.out.println("failed test case remove as pass retry:" + failedTestCase.getTestClass().toString());
                failedTestCases.remove();
            }
        }
    }
   }
}

RetryAnalizer:

public class MyRetryAnalyzer implements IRetryAnalyzer {
    private static int MAX_RETRY_COUNT = 3;

    AtomicInteger count = new AtomicInteger(MAX_RETRY_COUNT);

    public boolean isRetryAvailable() {
        return (count.intValue() > 0);
    }

    @Override
    public boolean retry(ITestResult result) {
        boolean retry = false;
        if (isRetryAvailable()) {
            System.out.println("Going to retry test case: " + result.getMethod() + ", " + (MAX_RETRY_COUNT - count.intValue() + 1) + " out of " + MAX_RETRY_COUNT);
            retry = true;
            count.decrementAndGet();
        }
        return retry;
    }
}

POM.xml - > Surefire配置:

这是你应该配置“覆盖”surefire监听器的地方,它有自己的计数器。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.18.1</version>
  <configuration>
    <suiteXmlFiles><suiteXmlFile>${basedir}/testng.xml</suiteXmlFile></suiteXmlFiles>
 <properties> 
   <property>
    <name>listener</name>
    <value>Utils.MyTestListenerAdapter,Utils.MyRetryAnalizer</value>
   </property>
 </properties>

另一答案

我最终选择了一个使用套件监听器的解决方案。

该解决方案可能无法完全清理TestNG /您的测试记录到控制台的内容,但如果您使用TestNG Jenkins插件,并且每次测试都先失败,然后成功,那么测试运行最终会变为绿色,即I猜是最重要的事情。

是的,我们运行mvn integration-test(不是mvn verify),让TestNG插件处理pass / fail。 The solution is quite similar / builds on what was posted here

import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.testng.ISuite;
import org.testng.ISuiteListener;
import org.testng.ISuiteResult;
import org.testng.ITestContext;

/**
 * {@link ISuiteListener} implementation to clean up duplicate test results caused by retrying tests using the
 * {@link RetryAnalyzer}
 */
public class SuiteResultListener implements ISuiteListener {

    private static final Logger LOG = LogManager.getLogger();

    @Override
    public void onStart(ISuite suite) {
    }

    @Override
    public void onFinish(ISuite suite) {
        LOG.info("Cleaning up duplicate test failures in suite '" + suite.getName() + "' ...");
        final Map<String, ISuiteResult> results = suite.getResults();
        int removedFailures = 0;
        for (ISuiteResult result : results.values()) {
            final ITestContext testContext = result.getTestContext();

            removedFailures += TestListenerUtil.cleanUpDuplicateFailures(testContext);
        }

        LOG.info("Removed " + removedFailures + " duplicate test failure(s) from suite '" + suite.getName() + "'");
    }
}

这是TestListenerUtil类中发生的魔力:

public static int cleanUpDuplicateFailures(ITestContext testContext) {
    final String testContextName = testContext.getName();
    int removedFailures = 0;

    LOG.info("Cleaning up failures in test context '" + testContextName + "' ...");
    final Set<ITestResult> failedTests = testContext.getFailedTests().getAllResults();
    if (failedTests.isEmpty()) {
        LOG.info("There are no failures in test context '" + testContextName + "'
");
    } else {
        // collect all id's from passed test
        final Set<Integer> passedTestIds = new HashSet<>();
        final Set<ITestResult> passedTests = testContext.getPassedTests().getAllResults();
        LOG.info("Analyzing " + passedTests.size() + " passed test(s)");
        for (ITestResult result : passedTests) {
            final int testId = TestListenerUtil.getId(result);
            passedTestIds.add(testId);
            LOG.info("  Passed test " + TestListenerUtil.getName(result) + ": #" + testId + " @ "
                    + getStartTime(result));
        }

        // check which failed test results should be removed
        final List<Integer> resultsToBeRemoved = new ArrayList<>();
        final Set<Integer> failedTestIds = new HashSet<>();

        LOG.info("Analyzing " + failedTests.size() + " failed test(s)");
        for (ITestResult result : failedTests) {
            final int testId = TestListenerUtil.getId(result);
            final String name = TestListenerUtil.getName(result);

            // if we saw this test pass or fail before we mark the result for deletion
            if (failedTestIds.contains(testId) || passedTestIds.contains(testId)) {
                LOG.info("  Adding test " + name + " to be removed: #" + testId + " @ " + getStartTime(result));
                resultsToBeRemoved.add(testId);
            } else {
                LOG.info("  Remembering failed test " + name + ": #" + testId + " @ " + getStartTime(result));
                failedTestIds.add(testId);
            }
        }

        // finally delete all duplicate failures (if any)
        final int duplicateFailures = resultsToBeRemoved.size();
        if (duplicateFailures > 0) {
            LOG.info("Cleaning up failed tests (expecting to remove " + resultsToBeRemoved.size()
                    + " result(s)) ...");
            for (ITestResult result : testContext.getFailedTests().getAllResults()) {
                final int testId = TestListenerUtil.getId(result);
                final String info = TestListenerUtil.getName(result) + ": #" + testId + " @ "
                        + getStartTime(result);
                if (resultsToBeRemoved.contains(testId)) {
                    LOG.info("  Removing failed test result " + info);
                    testContext.getFailedTests().removeResult(result);
                    resultsToBeRemoved.remove((Integer) testId);
                    removedFailures++;
                } else {
                    LOG.info("  Not removing failed test result " + info);
                }
            }
        }

        if (removedFailures == duplicateFailures) {
            LOG.info("Removed " + removedFailures + " failed test result(s) in '" + testContextName + "'
");
        } else {
            LOG.warn("Removed " + removedFailures + " failed test result(s) in '" + testContextName
                    + "' (expected to remove " + duplicateF

以上是关于通过测试监听器删除(复制)失败的TestNG结果的主要内容,如果未能解决你的问题,请参考以下文章

TestNG 中的非静态驱动程序和屏幕截图侦听器

不是失败的TestNG失败

将屏幕截图附加到 TestNG 失败的方法结果

TestNG Listener

Selenium Java(maven 项目):TestNG 结果与 ReportNG 不同

自动化断言失败后,测试用例还会继续执行吗