大家在运行自动化case的时候都会碰到失败的情况,有的时候可能是被测程序有bug,还有就是网络的问题,如果想采取失败的case再运行一次的机制,那么有bug的情况,即使再运行N次还是失败,那么如果是网络的问题,那你再运行一次可能就会执行成功(因为再次运行的话,这时候需要操纵的页面元素会正确的加载进来),这样会大大的加强了自动化脚本的健壮性。接下来通过代码来讲解这个机制的实现过程。
实际上这个机制是通过testng来实现的,虽然testng没有直接提供这种retry to run fail cases的功能,但是testng提供了实现这种功能的接口,它就是IRetryAnalyzer,一旦实现了接口里的方法retry(),就具备了这种功能,当retry()返回的值是true,那就表明该test是需要再运行一次,反之返回的结果是false,那就不需要再运行了该test了。具体的操作代码如下:
1 package com.cbmp.utility; 2 3 import org.testng.IRetryAnalyzer; 4 import org.testng.ITestResult; 5 import org.testng.Reporter; 6 7 public class RetryAnalyzer implements IRetryAnalyzer { 8 private int count = 0; 9 private int maxCount = 2; 10 11 @Override 12 public boolean retry(ITestResult result) { 13 if (!result.isSuccess()) { 14 if (count < maxCount) { 15 count++; 16 result.setStatus(ITestResult.SUCCESS); 17 String message = Thread.currentThread().getName() 18 + ": Error in " + result.getName() + " Retrying " 19 + (maxCount + 1 - count) + " more times"; 20 System.out.println(message); 21 Reporter.log(message); 22 return true; 23 } else { 24 result.setStatus(ITestResult.FAILURE); 25 } 26 } 27 return false; 28 } 29 }
着还不算完事,接着我们需要实现监听的接口IAnnotationTransformer,然后把实现的类赋值给@test的属性RetryAnalyzer,具体代码如下:
1 package com.cbmp.utility; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5 6 import org.testng.IAnnotationTransformer; 7 import org.testng.IRetryAnalyzer; 8 import org.testng.annotations.ITestAnnotation; 9 10 /** 11 */ 12 public class RetryListener implements IAnnotationTransformer { 13 14 /* (non-Javadoc) 15 * @see org.testng.IAnnotationTransformer#transform(org.testng.annotations.ITestAnnotation, java.lang.Class, java.lang.reflect.Constructor, java.lang.reflect.Method) 16 */ 17 @SuppressWarnings("rawtypes") 18 @Override 19 public void transform(ITestAnnotation annotation, Class testClass, 20 Constructor testConstructor, Method testMethod) { 21 22 IRetryAnalyzer retry = annotation.getRetryAnalyzer(); 23 if (retry == null) { 24 // annotation.setRetryAnalyzer(RetryAnalyzer.class); 25 //annotation.setRetryAnalyzer(RetryFail.class); 26 annotation.setRetryAnalyzer(RetryAnalyzer.class); 27 } 28 } 29 30 }
摘自官网的一个注意项,基于这个说法,我们只能使用该接口来修改@test的属性
IAnnotationTransformer only lets you modify a @Test annotation. If you need to modify another TestNG annotation (a configuration annotation, @Factory or @DataProvider), use an IAnnotationTransformer2.
最后我们还需要在testng的suite.xml文件添加一个listener标签
1 <suite name="CBMP"> 2 <listeners> 3 <listener class-name="com.cbmp.utility.RetryListener" /> 4 </listeners> 5 <test name="cbmp1" preserve-order="true" > 6 <classes> 7 <class name="com.cbmp.testcases.loginTestDemo"> 8 </class> 9 </classes> 10 </test> 11 </suite>
这样当你运行testng的时候,就会运行LoginTestDemo类里的标记为@test的方法,当这些方法失败的时候就会调用RetryListener里的retry方法,当retry的方法返回的结果是true的话就重新运行这些失败的方法,如果返回的是false就不会再运行。还有一个要注意的是,测试方法成功的话是不会调用RetryListener里的retry方法,这个是我在调试的时候发现的机制。
作为文章的收尾,下面展示的是test的代码片段,里面的断言是故意要失败的,以检测retry机制是否被触发
1 @Test(dependsOnMethods = "opencbmp", enabled = true) 2 public void noUserAndPwd(){ 3 try { 4 5 loginpage = PageFactory.initElements(driver, 6 LoginPage.class); 7 loginpage.verifyPageElements("CBMP Login Interface Page"); 8 loginpage.login("admin", "dawda"); 9 10 Assert.assertEquals(true, false); 11 12 13 } catch (Exception e) { 14 // TODO: handle exception 15 System.out.println(e.toString()); 16 } 17 18 }
待解决的问题:
- result.setStatus(ITestResult.SUCCESS),把当前失败的测试结果设置为成功,但是一直不能生效,这个问题比较困扰我
- 当触发retry to run fail case的时候,testng也会把重试运行的case也统计在内,这样就会造成运行后的testcase总数目不准确