testng跑失败用例重试
testng 提高用例通过率,失败用例要重新运行一次
步骤:
1、新建一个Retry 类,implements IRetryAnalyzer接口,这个类里面确定重跑次数,以及分析每次失败是否需要重新运行
import org.testng.IRetryAnalyzer; import org.testng.ITestResult; public class Retry implements IRetryAnalyzer { private int retryCount = 0; private int maxRetryCount = 1; @Override public boolean retry(ITestResult result) { if (retryCount < maxRetryCount) { System.out.println("Retrying test " + result.getName() + " with status " + getResultStatusName(result.getStatus()) + " for the " + (retryCount + 1) + " time(s)."); retryCount++; return true; } resetRetrycount(); // 每次跑完一条用例后,重置retryCount为0,这样dataProvider 数据驱动测试叶支持 return false; } public String getResultStatusName(int status) { String resultName = null; if (status == 1) resultName = "SUCCESS"; if (status == 2) resultName = "FAILURE"; if (status == 3) resultName = "SKIP"; return resultName; } public boolean isRetryAvailable() { return retryCount < maxRetryCount; } public void resetRetrycount() { retryCount = 0; } }
2、新建一个RetryListener类,implements IAnnotationTransformer 主要功能是监听事件
import java.lang.reflect.Constructor; import java.lang.reflect.Method; import org.testng.IAnnotationTransformer; import org.testng.IRetryAnalyzer; import org.testng.annotations.ITestAnnotation; public class RetryListener implements IAnnotationTransformer { @Override public void transform(ITestAnnotation testannotation, Class testClass, Constructor testConstructor, Method testMethod) { IRetryAnalyzer retry = testannotation.getRetryAnalyzer(); if (retry == null) { testannotation.setRetryAnalyzer(Retry.class); } } }
3、测试结果处理,testng运行结果中,去掉重复运行的用例,即不论这个用例跑多少遍,都算一个用例
import java.util.Set; import org.apache.log4j.Logger; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestNGMethod; import org.testng.ITestResult; public class TestListener implements ITestListener { private static org.apache.log4j.Logger logger = Logger.getLogger(ITestListener.class); @Override public void onFinish(ITestContext testContext) { // super.onFinish(testContext); // List of test results which we will delete later ArrayList<ITestResult> testsToBeRemoved = new ArrayList<ITestResult>(); // collect all id's from passed test Set<Integer> passedTestIds = new HashSet<Integer>(); for (ITestResult passedTest : testContext.getPassedTests().getAllResults()) { logger.info("PassedTests = " + passedTest.getName()); passedTestIds.add(getId(passedTest)); } Set<Integer> failedTestIds = new HashSet<Integer>(); for (ITestResult failedTest : testContext.getFailedTests().getAllResults()) { logger.info("failedTest = " + failedTest.getName()); // id = class + method + dataprovider int failedTestId = getId(failedTest); // if we saw this test as a failed test before we mark as to be // deleted // or delete this failed test if there is at least one passed // version if (failedTestIds.contains(failedTestId) || passedTestIds.contains(failedTestId)) { testsToBeRemoved.add(failedTest); } else { failedTestIds.add(failedTestId); } } // finally delete all tests that are marked for (Iterator<ITestResult> iterator = testContext.getFailedTests().getAllResults().iterator(); iterator .hasNext();) { ITestResult testResult = iterator.next(); if (testsToBeRemoved.contains(testResult)) { logger.info("Remove repeat Fail Test: " + testResult.getName()); iterator.remove(); } } } private int getId(ITestResult result) { int id = result.getTestClass().getName().hashCode(); id = id + result.getMethod().getMethodName().hashCode(); id = id + (result.getParameters() != null ? Arrays.hashCode(result.getParameters()) : 0); return id; }*/ public void onTestStart(ITestResult result) { } public void onTestSuccess(ITestResult result) { } public void onTestFailure(ITestResult result) { } public void onTestSkipped(ITestResult result) { } public void onTestFailedButWithinSuccessPercentage(ITestResult result) { } public void onStart(ITestContext context) { } }
4、testng xml中配置监听
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Default suite"> <listeners> <listener class-name="com.auto.listen1.RetryListener"/> <listener class-name="com.auto.listen1.TestListener"/> </listeners> <test verbose="2" name="Default test"> <classes> <class name="com.auto.listen1.NewTest"/> </classes> </test> <!-- Default test --> </suite> <!-- Default suite -->
5、新建一个测试类
package com.auto.listen1; import org.testng.annotations.Test; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; //@Listeners(value = MyTestListenerAdapter.class) public class NewTest { @Test(dataProvider = "dp") // @Test(retryAnalyzer = MyRetryAnalyzer.class,dataProvider = "dp") public void f(Integer n, String s) { System.out.println("ssssss:" + s); Assert.assertFalse(true); } } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { 1, "a" }, new Object[] { 2, "b" },new Object[] { 3, "c" },new Object[] { 4, "d" } }; } }
运行结果:
ssssss:a
Retrying test f with status FAILURE for the 1 time(s).
ssssss:a
ssssss:b
Retrying test f with status FAILURE for the 1 time(s).
ssssss:b
ssssss:b
Retrying test f with status FAILURE for the 1 time(s).
ssssss:b
ssssss:c
Retrying test f with status FAILURE for the 1 time(s).
ssssss:c
ssssss:c
Retrying test f with status FAILURE for the 1 time(s).
ssssss:c
ssssss:c
Retrying test f with status FAILURE for the 1 time(s).
ssssss:c
ssssss:d
Retrying test f with status FAILURE for the 1 time(s).
ssssss:d
ssssss:d
Retrying test f with status FAILURE for the 1 time(s).
ssssss:d
ssssss:d
Retrying test f with status FAILURE for the 1 time(s).
ssssss:d
ssssss:d
Retrying test f with status FAILURE for the 1 time(s).
ssssss:d
这个结果中,第一个参数a运行2遍,第二个参数b运行2*2=4遍,第三个参数c运行3*2=6遍,第四个参数d运行4*2=8遍,参数越多运行多余运行次数越多,这个是使用testng 6.9.10 版本问题,更新版本为6.9.13.6 后,运行结果正常如下:
ssssss:a
Retrying test f with status FAILURE for the 1 time(s).
ssssss:a
ssssss:b
Retrying test f with status FAILURE for the 1 time(s).
ssssss:b
ssssss:c
Retrying test f with status FAILURE for the 1 time(s).
ssssss:c
ssssss:d
Retrying test f with status FAILURE for the 1 time(s).
ssssss:d
每个失败用例都重试一次
版本问题参考:https://github.com/cbeust/testng/pull/740
https://github.com/cbeust/testng/pull/1104