TestNG監聽器實現失敗自動截圖、重跑、自定義html結果文件功能


【轉載自】http://kongqingyun123.blog.163.com/blog/static/637728352013854380867/

使用Testng框架搭建自動測試框架,經常會需要增加失敗自動截圖,以及失敗重跑功能,下面介紹一下不修改Testng的源碼,通過監聽器的方式來實現自動截圖、重跑、自定義Html結果文件功能。

自動截圖功能
1、新建一個Java類繼承TestListenerAdapter
2、重寫onTestFailure、onTestSkipped等方法,在這些方法中加入截圖操作
3、在testng.xml文件中配置自己編寫的監聽器類

<listeners>

<listener class-name="***.testng.TestngListener" />
</listeners>



public class TestngListener extends TestListenerAdapter {
private static Logger logger = Logger.getLogger(TestngListener.class);
public static final String CONFIG = "config.properties";

@Override
public void onTestFailure(ITestResult tr) {
super.onTestFailure(tr);
logger.info(tr.getName() + " Failure");
takeScreenShot(tr);
}

@Override
public void onTestSkipped(ITestResult tr) {
super.onTestSkipped(tr);
logger.info(tr.getName() + " Skipped");
takeScreenShot(tr);
}

@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);

}


/**
* 自動截圖,保存圖片到本地以及html結果文件中
*
* @param tr
*/
private void takeScreenShot(ITestResult tr) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
String mDateTime = formatter.format(new Date());
String fileName = mDateTime + "_" + tr.getName();
String filePath = OrangeiOS.driver.getScreenshotAs(fileName);
Reporter.setCurrentTestResult(tr);
Reporter.log(filePath);

//這里實現把圖片鏈接直接輸出到結果文件中,通過郵件發送結果則可以直接顯示圖片
Reporter.log("<img src=\"../" + filePath + "\"/>");

}

 

 



 

失敗自動重跑功能
1、新建Java類實現IRetryAnalyzer接口

public class TestngRetry implements IRetryAnalyzer {
private static Logger logger = Logger.getLogger(TestngRetry.class);
private int retryCount = 1;
private static int maxRetryCount;
private static ConfigReader config;
static {

//外圍文件配置最大運行次數
config = new ConfigReader(TestngListener.CONFIG);
maxRetryCount = config.getMaxRunCount();
logger.info("maxRunCount=" + (maxRetryCount));
}

@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;
}

}

2、具體的測試類中添加失敗重跑監聽

@Test(description = "***", retryAnalyzer = TestngRetry.class)


上面兩步就可以實現失敗自動重跑了,是不是比較方便,不過添加了重跑功能后會發現測試結果的郵件中用例的個數增加了,比如我只有一個用例,失敗重跑了2次,一共運行3次,測試結果中顯示的用例個數會是3個,那接下來就需要解決這個問題了。

首先解決TestNg生成的index.html文件中個數不對的問題,這個問題只需要在Testng監聽器的onFinish方法中,等所有用例運行完之后,檢查用例,按照class+method+dataprodiver的名稱生成hashcode獲取唯一id,如果fail的用例中存在重復的則在fail的用例中剔除掉,具體代碼如下:

@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());
// id = class + method + dataprovider
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;
}



當前失敗重跑也存在一些小問題:
1、setup中出現的錯誤直接是skip的,不會重跑
2、如果存在dataprodiver,則第二個參數以后的用例是不會重跑的
3、testng自帶生成的emailable-report.html文件中用例的個數也不對了,這個問題可以自行修改EmailableReporter.java文件


自定義emailable-report.html

emailable-report.html是Testng運行完成后自動生成的,經常運行結束后我們會把這個郵件發送給收件人,如果我們要修改這個文件內容怎么辦呢?

1、首先emailable-report.html文件的生成TestNG是實現了IReporter接口,那我們可以直接從源代碼中取出這個文件源代碼
https://github.com/cbeust/testng/blob/master/src/main/java/org/testng/reporters/EmailableReporter.java
2、針對源代碼進行自己修改
3、在build.xml文件中關閉使用默認的監聽器

 useDefaultListeners="false"

<testng outputDir="test-output" classpathref="http://kongqingyun123.blog.163.com/blog/runpath" haltonfailure="false" useDefaultListeners="false" >
<xmlfileset dir="." includes="${testngxml}.xml" />
</testng>

4、在testng.xml文件中添加自己重寫的監聽器路徑


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM