失敗用例的重跑,實踐

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章