我们通过重写testng的retry方法和transform方法来实现用例失败重跑的功能。
首先添加两个文件
public class TestngRetry implements IRetryAnalyzer { private static Logger logger = Logger.getLogger(TestngRetry.class); private static int maxRetryCount = 3; private int retryCount = 1; @Override public boolean retry(ITestResult result) { if (retryCount <= maxRetryCount) { String message = "Running retry for '" + result.getName() + "' on class " + this.getClass().getName() + " Retrying " + retryCount + " times"; logger.info(message); Reporter.setCurrentTestResult(result); Reporter.log("RunCount=" + (retryCount + 1)); retryCount++; return true; } return false; } }
RetryListener.java
public class RetryListener implements IAnnotationTransformer { @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { IRetryAnalyzer retry = annotation.getRetryAnalyzer(); if (retry == null) { annotation.setRetryAnalyzer(TestngRetry.class); } } }
添加以上两个文件之后,有两种方法可以使用我们的listener进行监听:
在Test标签中添加retryAnalyzer属性
@Test(retryAnalyzer = com.xxx.retry.RetryListener.class)
- 在testng.xml文件中配置listener
<test name="test1"> <listeners> <listener class-name="com.xxx.retry.RetryListener" /> <classes> <class name="com.xxx.test.NewTest" /> </classes> </test>
做完上面的工作,我们就可以实现失败重跑的功能了。但是,每次用例重跑之后,每次失败的结果也记录在运行结果中了,测试结果中运行的用例数增加了,不利于我们查看测试结果。因此,我们还需要把重复的用例去掉。
这个我们通过重写TestListenerAdapter中的onFinish方法实现:
TestngListener.java
public class TestngListener extends TestListenerAdapter { private static Logger logger = Logger.getLogger(TestngListener.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()); 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; } }
把listener添加到testng.xml中,当前testng.xml为:
<test name="test1"> <listeners> <listener class-name="com.xxx.retry.RetryListener" /> <listener class-name="com.xxx.retry.TestngListener" /> </listeners> <classes> <class name="com.xxx.test.NewTest" /> </classes> </test>
OK,结束。