失败用例的重跑,实践

1. 在Testng.xml配置文件,在Test标签下增加监听

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TC_Operation_Suite" parallel="none" preserve-order="true">
<test name="swiftcoder2_0.TC_Operation">
   <groups>
       <run>

     <include name ="test.workflow" /> //执行初始条件
             <include name ="groupa" /> //执行组名为groupa的所有用例
       </run>
   </groups>
<classes>
   <class name = "swiftcoder2_0.TC_Operation" />//要哪个测试用例类,执行以上group
</classes>
<listeners>
   <!-- put the listener class here -->
<listener class-name = "swiftcoder2_0.RetryListener" /> //增加RetryListener的监听

<listener class-name = "swiftcoder2_0.TestngListener" />  //增加TestngListener的监听
   </listeners>
</test> <!-- Test -->

</suite> <!-- Suite -->

2.增加RetryListener类

package swiftcoder2_0;
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 annotation, 
Class testClass, Constructor testConstructor, Method testMethod) {
// TODO Auto-generated method stub
IRetryAnalyzer retry = annotation.getRetryAnalyzer();
if(retry == null){
annotation.setRetryAnalyzer(TestngRetry.class); //设置RetryAnalyzer
}
}

3. 增加TestngRetry类

package swiftcoder2_0;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
import org.testng.log4testng.Logger;
import GL.GL;
public class TestngRetry implements IRetryAnalyzer{
private static Logger logger = Logger.getLogger(TestngRetry.class);
private int retryCount = 1;
private static int maxRetryCount;

@Override
public boolean retry(ITestResult result) {
//get the max retry count 
maxRetryCount = Integer.parseInt(GL.getString("maxRunCount")); //在config.properties文件中设置maxRunCount 值
// TODO Auto-generated method stub
if (retryCount <= maxRetryCount) {
String message = "running retry for  '" + result.getName() + "' on class " + this.getClass().getName() + " Retrying "
+ retryCount + " times";
logger.info(message);
retryCount++;
return true;
}

return false;
}

}


4. 增加TestngListener类

package swiftcoder2_0;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import org.testng.log4testng.Logger;
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 = 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();
}
}
}

}

}

5. 设置config.properties文件

maxRunCount=3

6. TC_Operation用例文件

package swiftcoder2_0;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;


import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;


import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;


import org.testng.annotations.BeforeTest;
import org.testng.annotations.Configuration;
import org.testng.annotations.Test;
import swiftcoder2_0.MultiOutputStream;
import swiftcoder2_0.Swiftcoder2_0;
import GL.GL;
import GL.Logs;
import swiftcoder2_0.TestngRetry;
public class TC_Operation {
//@variables
int c =0;
int a =0;
@BeforeTest
@Configuration(beforeTestClass= true, groups = {"test.workflow"})
public void SetUp() throws InterruptedException, IOException{ 
System.out.println("----Before Test--------");

}

@AfterTest
@Configuration(afterTestClass= true, groups = {"test.workflow"})
public void TearDown(){
System.out.println("----After Test--------");
}

@BeforeMethod
@Configuration(beforeTestMethod= true, groups = {"test.workflow"})
public void BeforeMethod() throws InterruptedException{
System.out.println("----Before Method--------");

}
@AfterMethod
@Configuration(afterTestMethod= true, groups = {"test.workflow"})
public  void AfterMethod() throws InterruptedException{
//close the instance of the web driver
GL.quitWebDriver(wd);
System.out.println("----After Method--------");
}
@Test(groups = {"groupa"}, retryAnalyzer = TestngRetry.class)
public void testa(){
a++;
if(a <=2 ){
Assert.fail();
}
System.out.println("testa");
}

@Test(groups = {"groupa"} ,retryAnalyzer = TestngRetry.class
public void testc(){
c++;
if(c <=3){

Assert.fail();

}
System.out.println("testc");
}

@Test(groups = {"groupb"}, retryAnalyzer = TestngRetry.class)
public void testb(){
System.out.println("testb");

}
@Test(groups = {"groupb"}, retryAnalyzer = TestngRetry.class)
public void testb_1(){
System.out.println("testb");

}

}

逻辑分析:

从testng_groups.xml加载RetryListener+TestngListener,2个监听类,在运行每个case后,调用

TestngRetry类和从TestngListener类执行结果,接着 将此结果传入到TestngRetry的retry函数中,如果Fail,当前用例连续执行最大次数为maxRunCount,如果Pass,则不需Retry调用。最后在TestngListener运行结果中删除同一case id no. 的重复用例,对每个用例结果只保留最后运行结果。

7. 运行结果

7.1 如果xml文件不加入TestngListener监听

[TestNG] Running:
  E:\Documents\QA.Management\automation\swiftcoder2_0\testng-groups.xml

----Before Test--------
----Before Method--------
----After Method--------
----Before Method--------
----After Method--------
----Before Method--------
testa
----After Method--------
----Before Method--------
----After Method--------
----Before Method--------
----After Method--------
----Before Method--------
----After Method--------
----Before Method--------
testc
----After Method--------
----After Test--------


===============================================
TC_Operation_Suite
Total tests run: 7, Failures: 5, Skips: 0

7.2 如果xml文件加入TestngListener监听

[TestNG] Running:
  E:\Documents\QA.Management\automation\swiftcoder2_0\testng-groups.xml


This is log file
----Before Test--------
----Before Method--------
----After Method--------
----Before Method--------
----After Method--------
----Before Method--------
testa
----After Method--------
----Before Method--------
----After Method--------
----Before Method--------
----After Method--------
----Before Method--------
----After Method--------
----After Test--------


===============================================
TC_Operation_GroupsSuite
Total tests run: 2, Failures: 1, Skips: 0
===============================================


说明:若需要每个用例,需要监听,需要一一增加@Test(groups = {"groupb"},retryAnalyzer = TestngRetry.class)

如果测试时,用例Fail,最多执行maxRunCount次,用例Pass,无需重跑


xml文件加入TestngListener监听作用:首先解决TestNg生成的index.html文件中个数不对的问题,这个问题只需要在Testng监听器的onFinish方法中,等所有用例运行完之 后,检查用例,按照class+method+dataprodiver的名称生成hashcode获取唯一id,如果fail的用例中存在重复的则在 fail的用例中剔除掉。

参考资料:

http://testng.org/doc/documentation-main.html#test-groups 

TestNG的官网资料 listeners的知识

http://www.ibm.com/developerworks/cn/opensource/os-cn-testinglistener/index.html 
实战 TestNG 监听器
http://www.yeetrack.com/?p=1015
testng增加失败重跑机制
http://testng.org/javadoc/ 

JavaDoc API资料

https://martinholladay.wordpress.com/2013/11/16/testng-adjusting-test-counts-on-retry/

TESTNG & WEBDRIVER – ADJUSTING TEST COUNTS ON RETRY


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值