TestNG监听机制
需求背景:失败案例进行截图
核心代码
13.1新建Listener包,新建TestRusultListener类
public class TestResultListener extends TestListenerAdapter{
@Override
public void onTestFailure(ITestResult tr) {
// TODO Auto-generated method stub
super.onTestFailure(tr);
//编写自定义内容
//filePath命名解决:
//保存路径,保存在项目文件夹,所以要获取项目路径
String filePath = System.getProperty("user.dir")+"\\target\\screenshot\\";
//获取时间戳
String fileName = System.currentTimeMillis()+".png";
WebDriverUtils.takeScreenshot(filePath+fileName);
}
}
13.2修改testng.xml,使监听器生效
<listeners>
<listener class-name = "监听类路径"></listener>
</listeners>
需求背景:截图嵌入allure报表
核心代码
13.3新建AllureReportListener类
注意:记得新增的监听类都要去xml对应添加listener标签对
public class AllureReportListener implements IHookable{
@Override
public void run(IHookCallBack callBack, ITestResult testResult) {
// TODO Auto-generated method stub
//执行testng的@test注解
callBack.runTestMethod(testResult);
//如果@test测试案例结果出现异常,即案例失败
if(testResult.getThrowable() != null) {
//调用截图方法,进行截图
saveScreenshot();
}
}
//嵌入allure报表的通过@Attachment附件功能,可参考allure官网
@Attachment(value = "Page screenshot", type = "image/png")
public byte[] saveScreenshot() {
return WebDriverUtils.takeScreenshot();
}
}
对应修改WebDriverUtils类,使返回一个byte数组
//新建一个截图方法返回byte数组,因为allure报表生成需要
public static byte[] takeScreenshot() {
//强转,为什么能强转?因为WebDriver extents RemoteWebDriver,而RemoteWebDriver implements TakesScreenshot
TakesScreenshot screenshot = (TakesScreenshot)driver;
//截图保存成BYTES
byte[] arr = screenshot.getScreenshotAs(OutputType.BYTES);
return arr;
}
问题解决
13.1截图未嵌入报表
忘记加监听配置,testng监听对中加AllureReportListener
需求背景:失败案例重试
核心代码
web自动化不够稳定,提高成功率
13.4新建一个TestRetry
public class TestRetry implements IRetryAnalyzer{
@Override
public boolean retry(ITestResult result) {
// testng框架自带,默认失败不会重试,把返回值改为true,则会重试
return true;
}
}
测试案例关联失败监听
@Test(retryAnalyzer = TestRetry.class)
引发问题:失败则返回为真,如果失败了,就一直重试
13.5增加重试次数逻辑
public class TestRetry implements IRetryAnalyzer{
Logger logger = Logger.getLogger(TestRetry.class);
private int maxRetryCount = 2;
private int currentRetryCount = 0;
@Override
public boolean retry(ITestResult result) {
if(currentRetryCount < maxRetryCount) {
currentRetryCount++;
logger.info("========================================这是第【"+currentRetryCount+"】次重试===========================");
return true;
}else {
return false;
}
}
}
13.6设置全局失败监听重试
新建一个TestRetryListener类,implements IAnnotationTransformer,可以获取到@Test里的注解,并且改变注解值,这个也需要在xml监听标签对中添加
public class TestRetryListener implements IAnnotationTransformer{
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
//获取testng@test里的RetryAnalyzer注解
IRetryAnalyzer analyzer = annotation.getRetryAnalyzer();
//如果没有这个注解,则设置这个注解为自定义的retry类,这样就实现了针对全部test的重试,而不用一个一个test去添加注解
if(analyzer == null) {
annotation.setRetryAnalyzer(TestRetry.class);
}
}
}
问题解决
13.2监听重试和dataprovider多行数据冲突(未解决)
dataprovider中有多行数据时,多次执行同一个@Test时,会被算成重试。
解决方案:当dataprovider中的一行数据被执行完后,重试次数要恢复到初始值
public class TestRetry implements IRetryAnalyzer{
Logger logger = Logger.getLogger(TestRetry.class);
private int maxRetryCount = 2;
public static int currentRetryCount = 1;
@Override
public boolean retry(ITestResult result) {
logger.info("==================这是第【"+currentRetryCount+"】次重试===========================");
if(currentRetryCount <= maxRetryCount) {
currentRetryCount++;
logger.info("==================有运行到重试方法===========================");
return true;
}else {
return false;
}
}
}
修改TestResultListener 类
public class TestResultListener extends TestListenerAdapter{
@Override
public void onTestFailure(ITestResult tr) {
//省略其他功能重复截图
//dataprovider中一行数据全部重试运行次数达到最大值了也还是失败的话,把失败重试次数置为1,避免下一行数据重试次数计数出问题
TestRetry.currentRetryCount = 1;
}
@Override
public void onTestSuccess(ITestResult tr) {
// TODO Auto-generated method stub
super.onTestSuccess(tr);
//
//dataprovider中一行数据运行成功后,把失败重试次数置为1,避免下一行数据重试次数计数出问题
TestRetry.currentRetryCount = 1;
}
}
这样改了代码后,虽然不会把重试次数计算错了,但是遇到多行情况,出错的数据就程序报错,一次都不执行了,耗时的事情先放一放,先捋清楚大块,有空在纠小细节
学习心得
通过监听功能的学习,写代码更好的理解了java中继承父类和实现接口的一点区别
1>继承父类(别人写好的class),关键字是extends,父类里有很多方法,子类继承后可以直接使用父类方法,如果想针对父类方法个性化,就对应选择重写父类方法
2>实现接口(别人写好的interface),关键字是implements,接口里也有方法,但是子类实现接口后,必须要重写接口方法,等待子类去实现具体方法体