在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次,点击每一次的执行结果,都会展示错误截图:
至此,失败用例截图与失败用例重试已经集成完成。