在UI自動化測試用例執行過程中,經常會有很多不確定的因素導致用例執行失敗,比如網絡原因、環境問題等,所以我們有必要引入重試機制(失敗重跑),來提高測試用例執行穩定性。
准備工作:我們在進行失敗截圖保存到本地的時候,需要用到FileUtils類,該類是在commons-io包下的,所以我們需要先引入依賴:
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
一:失敗用例截圖:
1、創建一個用例失敗截圖監聽類(TestResultListener,名字自起)實現IHookable接口,實現run方法。 IHookable接口的作用:動態替換每一個被@Test注解標注的方法,即每當運行到@Test注解的方法的時候,就會執行該類的邏輯。
代碼如下:
@Override
public void run(IHookCallBack iHookCallBack, ITestResult iTestResult) {
//保證@Test注解標注的測試方法能夠正常執行
iHookCallBack.runTestMethod(iTestResult);
//判斷用例結果是否異常
if(iTestResult.getThrowable() != null){
//testResult參數提供了getInstance方法,可以獲取當前測試類的實例(對象)
BaseTest baseTest = (BaseTest) iTestResult.getInstance();
RemoteWebDriver driver = baseTest.driver;
//保存到allure報表中
saveScreenshotToAllure(takeScreenshotAsByte(driver));
//保存到本地
takeScreenshot(driver,"test_"+System.currentTimeMillis());
}
}
2、在testng.xml文件中添加listener標簽使監聽器生效,代碼如下:
<!--使監聽器生效-->
<listeners>
<listener class-name="com.lrc.listener.TestResultListener"></listener>
</listeners>
3、在Listener類中添加@Attachment注解方法,將截圖保存到allure報表中
@Attachment(value = "screenshot",type = "image/png")
public byte[] saveScreenshotToAllure(byte[] data){
//返回的字節數組的數據 作為附件添加到Allure報表中--》@Attachment注解來實現的
return data;
}
4、在Listener類中提供生成字節數組的截圖數據
/**
* 生成字節數組的截圖數據
* @param driver
* @return
*/
public byte[] takeScreenshotAsByte(RemoteWebDriver driver){
byte[] data = driver.getScreenshotAs(OutputType.BYTES);
return data;
}
5、在Listener類中提供生成普通文件的截圖數據,用於在本地也生成截圖
/**
* 生成截圖以普通文件的形式,並且保存到本地
* @param driver
* @param fileName
*/
public void takeScreenshot(RemoteWebDriver driver, String fileName){
File srcFile = driver.getScreenshotAs(OutputType.FILE);
File destFile = new File(System.getProperty("user.dir")+"\\screenshot\\"+fileName+".png");
try {
FileUtils.copyFile(srcFile,destFile);
} catch (IOException e) {
e.printStackTrace();
}
}
整個失敗用例截圖類的代碼:
package com.lrc.listener;
import com.lrc.common.BaseTest;
import io.qameta.allure.Attachment;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;
import java.io.File;
import java.io.IOException;
/**
* @param
* @author lrc
* @create 2021/12/19
* @return
* @description
**/
public class TestResultListener implements IHookable {
@Override
public void run(IHookCallBack iHookCallBack, ITestResult iTestResult) {
//保證@Test注解標注的測試方法能夠正常執行
iHookCallBack.runTestMethod(iTestResult);
//判斷用例結果是否異常
if(iTestResult.getThrowable() != null){
//testResult參數提供了getInstance方法,可以獲取當前測試類的實例(對象)
BaseTest baseTest = (BaseTest) iTestResult.getInstance();
RemoteWebDriver driver = baseTest.driver;
//保存到allure報表中
saveScreenshotToAllure(takeScreenshotAsByte(driver));
//保存到本地
takeScreenshot(driver,"test_"+System.currentTimeMillis());
}
}
@Attachment(value = "screenshot",type = "image/png")
public byte[] saveScreenshotToAllure(byte[] data){
//使用@Attachment注解來實現的返回的字節數組的數據 作為附件添加到Allure報表中
return data;
}
/**
* 生成字節數組的截圖數據
* @param driver
* @return
*/
public byte[] takeScreenshotAsByte(RemoteWebDriver driver){
byte[] data = driver.getScreenshotAs(OutputType.BYTES);
return data;
}
/**
* 生成截圖以普通文件的形式,並且保存到本地
* @param driver
* @param fileName
*/
public void takeScreenshot(RemoteWebDriver driver, String fileName){
File srcFile = driver.getScreenshotAs(OutputType.FILE);
File destFile = new File(System.getProperty("user.dir")+"\\screenshot\\"+fileName+".png");
try {
FileUtils.copyFile(srcFile,destFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
整個testng.xml的代碼:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite" parallel="tests" thread-count="2">
<!--使監聽器生效-->
<listeners>
<listener class-name="com.lrc.listener.TestResultListener"></listener>
</listeners>
<test name="測試">
<classes>
<class name="com.lrc.testcases.TestBaidu3"/>
</classes>
</test>
</suite>
下面,我們特意設置用例執行失敗,查看用例失敗截圖是否會生成在allure報表中生成與在本地生成
執行結果:
(1)在本地文件有生成失敗用例截圖
在allure報表里也有生成失敗用例截圖:
二:失敗用例重試
1、創建用例重試監聽類(RetryListener,名字自起)實現testng包下的IRetryAnalyzer類,重寫retry方法。
package com.lrc.listener;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
/**
* @param
* @author lrc
* @create 2021/12/20
* @return
* @description
**/
public class RetryListener implements IRetryAnalyzer {
//最大重試次數
private int maxRetryCount=3;
//當前的重試次數
private int currentRetryCount=0;
@Override
public boolean retry(ITestResult result) {
//限制重試的最大次數,否則會進入死循環
if(currentRetryCount < maxRetryCount) {
//如果當前的重試次數沒有達到限制,就去執行重試機制
currentRetryCount++;
return true;
}else {
return false;
}
}
}
2、添加一個全局注解屬性修改的類,用於使@Test注解每次都能擁有retryAnalyzer屬性,可以減去每個@Test注解都要配置retryAnalyzer屬性操作
package com.lrc.listener;
import org.testng.IAnnotationTransformer;
import org.testng.IRetryAnalyzer;
import org.testng.annotations.ITestAnnotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @param
* @author lrc
* @create 2021/12/20
* @return
* @description
**/
public class GlobalAnnotationTransformer implements IAnnotationTransformer {
//通過實現IAnnotationTransformer接口可以動態的修改@Test注解的屬性
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
// 獲取@Test注解的RetryAnalyzer屬性對象
IRetryAnalyzer iRetryAnalyzer = annotation.getRetryAnalyzer();
if (iRetryAnalyzer == null) {
annotation.setRetryAnalyzer(RetryListener.class);
}
}
}
3、在testng.xml中添加listener標簽,使得全局注解修改監聽類生效
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite" parallel="tests" thread-count="2">
<!--使監聽器生效-->
<listeners>
<listener class-name="com.lrc.listener.TestResultListener"></listener>
<listener class-name="com.lrc.listener.GlobalAnnotationTransformer"></listener>
</listeners>
<test name="測試">
<classes>
<class name="com.lrc.testcases.TestBaidu3"/>
</classes>
</test>
</suite>
下面,我們再來看看失敗用例是否會重新運行,最大運行4次,由於上面我特意斷言每個用例都失敗,所以每個用例都應該運行4次:
每次用戶執行失敗,都會在本地生成失敗截圖,如下:
allure報表也會有失敗截圖,並且監聽了當前用例失敗重跑了幾次:
在allure報表中看到Retries被重復執行了3次,點擊每一次的執行結果,都會展示錯誤截圖:
至此,失敗用例截圖與失敗用例重試已經集成完成。