需要了解TestNG基础使用方法的,请移步TestNG官网
目标:收集TestNG框架下的接口自动化测试结果
不拖泥带水,复制粘贴就能完成。支持自定义注解
TestNG中最终都会经过监听器生成报告。
需要重写监听器,将测试结果进行收集。
一、实现IReporter, ISuiteListener接口
package com.base.test.tng.common;
import org.testng.IReporter;
import org.testng.ISuite;
import org.testng.ISuiteListener;
import org.testng.xml.XmlSuite;
import java.util.List;
/**
* @Description:
* 最后执行generateReport
* @Author: Joe Throne
* @CreatedTime: 2022-02-03 23:26
* TODO:
*/
public class BaseSuitesListener implements IReporter,ISuiteListener {
@Override
public void generateReport(List<XmlSuite> list, List<ISuite> list1, String s) {
System.out.println("hello genera ");
}
@Override
public void onStart(ISuite iSuite) {
System.out.println("hello start " + iSuite.getName());
}
@Override
public void onFinish(ISuite iSuite) {
System.out.println("hello finish " + iSuite.getAllMethods().size());
}
}
注意:这里需要了解套件信息,不同的套件写法会有完全不同的执行次数
二、分析&结论
强烈建议先看一下 TestNG中xml套件的两种写法对比 ,因为套件的写法不同,会导致OnStart调用的次数发生差异。
思路:那不管怎么样,generateReport方法最后都是最后执行,并且只执行一次。只有当不同的套件写法时,onStart方法和onFinish方法会执行多次。
结论:因此。我们在OnStart方法中初始化当前总套件执行时需要的必要参数,在OnFinish方法中通过集合汇总到所有的测试结果,最后在generateReport方法中进行解析,注解的信息可以通过反射拿到。
三、定义 最终测试结果 实体类
@Data
public class FinalTestResult implements Serializable {
private int testName; //当前项目的执行名称
private int passedCount = 0; //成功的case数
private int skippedCount = 0; //执行跳过的case数
private int failedCount = 0; //失败的case数
private long startTime = 0; //开始执行套件的时间
private long endTime = 0; //执行结束的时间
private String env; //执行的环境信息
private int projectId; //项目的id,用于平台识别信息来源
private int domain; //所属域的id,用于平台识别信息来源
private String operator; //执行人
private List<ResultMethodDetailEntity> detailEntities; //以method为单位的最终结果信息
private Map<String,SuiteResultCount> suiteResultCountMap; //以套件为单位的最终信息(只有数量)
private Set<String> urlSet; //以method为单位的最终结果信息
}
其中detailEntities是一个List集合,包含了所有成功、失败和跳过的case详细信息,其实体类如下:
@Data
public class ResultMethodDetailEntity implements Serializable{
private String caseClass; //当前case所属的class类名
private String caseMethod; //当前case的方法名称
private Integer runStatus; //当前case执行的结果
private Long startTime; //case开始执行的时间
private Long endTime; //case执行结束的时间
private String failLog; //case执行失败时的Log信息
private String failMsg; //case执行失败时的Msg信息
private int assertNum; //case中断言的数量
private String author; //当前case的注解中 作者信息
private String desc; //当前case的描述
private boolean isBVTCase; //当前case的注解中 是否是bvt用例
private ApiGan apiGan; //当前case的执行时的api信息,包含host、url、服务名称等
}
四、对OnStart方法进行改造
@Override
public void onStart(ISuite iSuite) {
//获取整个套件执行的开始时间
long startTime = System.currentTimeMillis();
//为了兼容多xml套件写法,防止多线程进入OnStart方法,为了获取最准确的项目启动时间
if(finalTestResult.getStartTime() == 0 || startTime < finalTestResult.getStartTime()){
//如果项目时间还是0 或者 获取的时间小于存在的项目时间(多线程) 则进行修改现存的时间值
finalTestResult.setStartTime(startTime);
}
//进行必要的初始化
finalTestResult.setEnv(Constant.ENV);
finalTestResult.setDomain(Constant.DOMAIN.DOMAIN_1);
finalTestResult.setProjectId(Constant.PROJECT_ID);
finalTestResult.setOperator("Joe Throne");
}
五、对OnFinish方法进行改造
@Override
public void onFinish(ISuite iSuite) {
this.finalTestResult.setDetailEntities(new ArrayList<>()); //将最终结果集的结果List进行初始化
this.finalTestResult.setUrlSet(new HashSet<String>()); //将最终结果集的Url集合 进行初始化
ResultMethodDetailEntity detailEntity; //声明一个case的详细结果
//对收集到的结果进行遍历
for(Iterator iter = this.iTestResults.iterator(); iter.hasNext(); this.finalTestResult