写在前面
这个重跑,维度为类,如果是数据驱动,部分需要修改,我已列出,但是去重部分还有问题没有解决,无法合并同一类下面的同一个重跑的用例,比如失败3次,希望是记录1次失败,但是目前是会删除这个失败的记录,只记录成功的。如果有大佬看见,知道怎么解决,麻烦评论一下,万分感谢!
新建一个类TestCaseRetry,implements IRetryAnalyzer接口。该类的作用是设定失败的用例重跑需要重新运行的次数,设定一个运行次数,设定一个最大执行次数,当运行次数超过最大执行次数的时候,说明重跑完成。
retry方法返回值如果为true说明重跑未完成,返回值为false,说明重跑完成
public class TestCaseRetry implements IRetryAnalyzer { private Logger logger = Logger.getLogger(TestCaseRetry.class); //当前正在进行的重试次数 public static int currentCount = 1; //允许重试的最大次数 private int maxCount = 2; @Override //如果返回为true的话,则执行retry public boolean retry(ITestResult iTestResult) { logger.info("当前重试次数是【" + currentCount + "】"); if (currentCount <= maxCount) { logger.info("当前测试方法【" + iTestResult.getName() + "】执行失败,进入失败用例重试模式,正在进行第【" + currentCount + "】次重试"); currentCount++; return true; } return false; } }
新建一个类RetryListener,implements IAnnotationTransformer接口。该类的作用是用来监听所有的测试方法是否有retryAnalyzer注解属性,如果有该属性则不会执行我们设定的重跑机制(局部重跑的优先级比全局的高)。
public class RetryListener implements IAnnotationTransformer { @Override public void transform(ITestAnnotation iTestAnnotation, Class aClass, Constructor constructor, Method method) { //1.初始化IRetryAnalyzer对象 IRetryAnalyzer iRetryAnalyzer = iTestAnnotation.getRetryAnalyzer(); //判断测试方法是否设置重跑属性 if (iRetryAnalyzer == null) { //为空说明用例方法里面未设置重跑,则按照全局设置进行用例重跑 //如果用例方法设置了注解属性retryAnalyzer,则按照注解的重跑 iTestAnnotation.setRetryAnalyzer(TestCaseRetry.class); } } }
将监听类RetryListener添加到testng.xml文件中
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="app_auto"> <test name="login"> <classes> <class name="cases.LoginTest"></class> </classes> </test> <!--配置监听器--> <listeners> <!--监听用例执行情况--> <listener class-name="listener.CustomListener"></listener> <!--对用例方法执行进行监听是否需要重试--> <listener class-name="listener.RetryListener"></listener> </listeners>
新建一个CustomListener类,implements TestListenerAdapter接口,重写其中的onTestFailure和onTestSuccess方法。这两个方法为用例执行以后失败和成功分别调用的方法,比如用例执行失败需要截图,就可以在onTestFailure方法里面去实现,这样用例执行失败以后,会进入该方法完成截图操作。而我们只需要在这两个方法里面将对面的运行重跑次数恢复初始值即可。这样不管重跑几次的失败用例执行结果是成功还是失败都必然会让重跑次数恢复默认值,其他失败用例再次执行重跑的时候就可以不受影响。
注意:这里的重置次数会以类为维度,就是说,如果你的Case下面用了数据驱动CSV等,那么会重复执行一条用例,死循环。
public class CustomListener extends TestListenerAdapter { Logger logger = Logger.getLogger(CustomListener.class); @Override public void onTestFailure(ITestResult tr) { super.onTestFailure(tr);//如果测试用例执行完所有重试以后依然失败的话,重新设置currentCount为初始值,方便其他用例执行重试 logger.info("用例执行失败,重试机制的次数恢复初始值"); TestCaseRetry.currentCount = 1; } @Override public void onTestSuccess(ITestResult tr) { //如果测试用例执行重试的时候,执行成功了,也需要设置currentCount为初始值,方便其他用例执行重试 logger.info("用例执行成功,重试机制的次数恢复初始值"); TestCaseRetry.currentCount = 1; super.onTestSuccess(tr); }
如果为数据驱动,按下面这么写不会有死循环,并且可以重试多次。
public class TestCaseRetry implements IRetryAnalyzer { private Logger logger = Logger.getLogger(TestCaseRetry.class); //当前正在进行的重试次数 public static int currentCount = 1; //允许重试的最大次数 private int maxCount = 2; @Override //如果返回为true的话,则执行retry public boolean retry(ITestResult iTestResult) { logger.info("当前重试次数是【" + currentCount + "】"); if (currentCount <= maxCount) { logger.info("当前测试方法【" + iTestResult.getName() + "】执行失败,进入失败用例重试模式,正在进行第【" + currentCount + "】次重试"); currentCount++; return true; } currentCount = 1; return false; } }
这里可能会有另一个testNG的版本问题,版本为6.9.10的时候,同样的用例,第一条数据执行了3次,第二条数据执行了6次,第三条数据执行了9次,越往后面的数据执行,运行次数就越多。这是testNG版本问题,更换为高版本以后搞定!使用6.14.3正常!
但是,用例重跑之后,失败的结果也记录在运行结果中了,测试结果中运行的用例数增加了,不利于我们查看测试结果。因此,我们还需要把重复的用例去掉。
解决办法就是重写onFinish
public class TestngListener extends TestListenerAdapter { private static Logger logger = Logger.getLogger(TestngListener.class); @Override public void onTestFailure(ITestResult tr) { super.onTestFailure(tr); logger.info(tr.getName() + " Failure"); } @Override public void onTestSkipped(ITestResult tr) { super.onTestSkipped(tr); logger.info(tr.getName() + " Skipped"); } @Override public void onTestSuccess(ITestResult tr) { super.onTestSuccess(tr); logger.info(tr.getName() + " Success"); } @Override public void onTestStart(ITestResult tr) { super.onTestStart(tr); logger.info(tr.getName() + " Start"); } @Override public void onFinish(ITestContext testContext) { super.onFinish(testContext); Iterator<ITestResult> listOfFailedTests = testContext.getFailedTests().getAllResults().iterator(); while (listOfFailedTests.hasNext()) { ITestResult failedTest = (ITestResult) listOfFailedTests.next(); ITestNGMethod method = failedTest.getMethod(); if (testContext.getFailedTests().getResults(method).size() > 1) { listOfFailedTests.remove(); } else { if (testContext.getPassedTests().getResults(method).size() > 0) { listOfFailedTests.remove(); } } } } }
重新添加监听
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="app_auto"> <test name="login"> <classes> <class name="cases.LoginTest"></class> </classes> </test> <!--配置监听器--> <listeners> <!--监听用例执行情况--> <listener class-name="listener.CustomListener"></listener> <!--对用例方法执行进行监听是否需要重试--> <listener class-name="listener.RetryListener"></listener> <!--去除重复执行--> <listener class-name="listener.TestngListener"></listener> </listeners>
又但是。。这里去除重复是以类为维度,如果你是数据驱动,如果这个类下面百分之20用例失败,那百分之20的失败用例会被抹去,不被记录。只显示成功的用例。
到这里,重跑的配置算完成了。如果要使用重跑的话,只需要在@test后面配置一下
retryAnalyzer = TestCaseRetry.class
@Test(dataProvider = "DriverDataProvider",retryAnalyzer = TestCaseRetry.class)
这里这个重跑建议还是Junit的好,配置方面比TestNg要方便,可以直接使用MVN里的rerunFailingTestsCount属性进行。
参考:http://maven.apache.org/surefire/maven-surefire-plugin/examples/rerun-failing-tests.html