retryAnalyzer 后如何将 TestNG DefaultSuite 结果发送到 Maven Surefire 插件
Posted
技术标签:
【中文标题】retryAnalyzer 后如何将 TestNG DefaultSuite 结果发送到 Maven Surefire 插件【英文标题】:How to send TestNG DefaultSuite results after retryAnalyzer to Maven Surefire Plugin 【发布时间】:2014-11-26 13:08:24 【问题描述】:我确实搜索了很多,这是我得到的最接近的答案,但并没有解决我的问题。 TestNG retrying failed tests doesn't output the correct test results
但我需要将上述问题从 TestNG 扩展到 Maven。请帮忙。
我的项目堆栈:TestNG、Maven surefire 插件、Maven。我正在从命令行运行测试 - “mvn clean compile test”。我正在使用重试分析仪重新运行第二次通过的失败测试。我已经能够使用 CustomListener 来更新存储在 TestNG 的 testcontext 中的结果(基于 *** 中的解决方案)。当我作为 TestNG 套件运行测试时,这一点得到了证实。
但是当我运行“mvn clean compile test”时,所有的重试都算作单独的测试并且构建总是失败。如何使 TestNG 仅将最终套件结果发送到 Maven Surefire 插件?
测试执行:
============================================
DefaultTest
Total tests run: 4, Failures: 2, Skips: 0
============================================
============================================
DefaultSuite
Total tests run: 2, Failures: 0, Skips: 0
============================================
MAVEN 执行:
Tests run: 4, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 0.292 sec <<< FAILURE!
Results :
Failed tests:
test1(foo.TestClass1)
test1(foo.TestClass1)
Tests run: 4, Failures: 2, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
由于重试,构建通过。如何将 TestNG 重试套件结果反映到 Maven 上?
【问题讨论】:
嗨!你的问题解决了吗?我将问题追踪到 maven testng runner,它将自己的侦听器安装到 testng 中。它忽略最终的计数器调整,因为它维护自己的计数器 这里有同样的问题。任何想法或更新?谢谢! 【参考方案1】:Some suit info is incorrect, but maven surefire works properly
maven-surefire-plugin 2.16
testng 6.8.8
// ===== InvokedMethodListener =====
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
public class InvokedMethodListener implements IInvokedMethodListener
@Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult)
@Override
public void afterInvocation(IInvokedMethod method, ITestResult testResult)
RetryAnalyzer retryAnalyzer = (RetryAnalyzer)testResult.getMethod().getRetryAnalyzer();
if (retryAnalyzer == null || retryAnalyzer.isFailed())
return;
if (testResult.getStatus() == ITestResult.FAILURE)
testResult.setStatus(ITestResult.SUCCESS);
// ===== RetryAnalyzer =====
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
import org.testng.Reporter;
public class RetryAnalyzer implements IRetryAnalyzer
private int count = 0;
private int maxCount = 2;
@Override
public boolean retry(ITestResult result)
if (!result.isSuccess())
if (count < maxCount)
count++;
return true;
return false;
public boolean isFailed()
return count >= maxCount;
// ===== BaseTest =====
@Listeners( ..InvokedMethodListener.class )
public abstract class BaseTest
...
@BeforeSuite(alwaysRun = true)
public void beforeSuite(ITestContext context)
for (ITestNGMethod method : context.getAllTestMethods())
method.setRetryAnalyzer(new RetryAnalyzer());
【讨论】:
【参考方案2】:终于明白了。我使用此代码:
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();
重试分析器:
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>
【讨论】:
我的测试框架中有类似的设置,但出现以下错误:Listener package.RerunTestAnalyzer@6fda4e65 必须是 ITestListener、ISuiteListener、IReporter、IAnnotationTransformer、IMethodInterceptor 或 IInvokedMethodListener 之一。你知道我该如何解决这个错误吗? 经过一番研究,我发现我们不需要在 pom.xml 中声明我们自定义的 IRetryAnalyzer 实现。由于它不是典型的 TestNG 监听器,所以上面的错误是有效的。此外,纠正执行测试总数的逻辑在 TestListenerAdapter 实现中。只要我们在 pom 文件中声明这个监听器,Maven 就会打印出正确数量的执行测试。以上是关于retryAnalyzer 后如何将 TestNG DefaultSuite 结果发送到 Maven Surefire 插件的主要内容,如果未能解决你的问题,请参考以下文章
Jenkins如何集成运行testng.xml文件的解决方案
编辑后的帖子如何从main()运行TestNG测试,我已经编写了主类 - 但是现在呢?