packagecom.qa.report;importcom.aventstack.extentreports.ExtentReports;importcom.aventstack.extentreports.ExtentTest;importcom.aventstack.extentreports.ResourceCDN;importcom.aventstack.extentreports.Status;importcom.aventstack.extentreports.model.TestAttribute;importcom.aventstack.extentreports.reporter.ExtentHtmlReporter;importcom.aventstack.extentreports.reporter.configuration.ChartLocation;import org.testng.*;importorg.testng.xml.XmlSuite;importjava.io.File;import java.util.*;public class ExtentTestNGReporterListener implementsIReporter{//生成的路径以及文件名
private static final String OUTPUT_FOLDER = "test-output/";private static final String FILE_NAME = "index.html";privateExtentReports extent;
@Overridepublic void generateReport(List xmlSuites, Listsuites, String outputDirectory) {
init();boolean createSuiteNode = false;if(suites.size()>1){
createSuiteNode=true;
}for(ISuite suite : suites) {
Map result =suite.getResults();//如果suite里面没有任何用例,直接跳过,不在报告里生成
if(result.size()==0){continue;
}//统计suite下的成功、失败、跳过的总用例数
int suiteFailSize=0;int suitePassSize=0;int suiteSkipSize=0;
ExtentTest suiteTest=null;//存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。
if(createSuiteNode){
suiteTest=extent.createTest(suite.getName()).assignCategory(suite.getName());
}boolean createSuiteResultNode = false;if(result.size()>1){
createSuiteResultNode=true;
}for(ISuiteResult r : result.values()) {
ExtentTest resultNode;
ITestContext context=r.getTestContext();if(createSuiteResultNode){//没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。
if( null ==suiteTest){
resultNode=extent.createTest(r.getTestContext().getName());
}else{
resultNode=suiteTest.createNode(r.getTestContext().getName());
}
}else{
resultNode=suiteTest;
}if(resultNode != null){
resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName());if(resultNode.getModel().hasCategory()){
resultNode.assignCategory(r.getTestContext().getName());
}else{
resultNode.assignCategory(suite.getName(),r.getTestContext().getName());
}
resultNode.getModel().setStartTime(r.getTestContext().getStartDate());
resultNode.getModel().setEndTime(r.getTestContext().getEndDate());//统计SuiteResult下的数据
int passSize =r.getTestContext().getPassedTests().size();int failSize =r.getTestContext().getFailedTests().size();int skipSize =r.getTestContext().getSkippedTests().size();
suitePassSize+=passSize;
suiteFailSize+=failSize;
suiteSkipSize+=skipSize;if(failSize>0){
resultNode.getModel().setStatus(Status.FAIL);
}
resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize));
}
buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL);
buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP);
buildTestNodes(resultNode,context.getPassedTests(), Status.PASS);
}if(suiteTest!= null){
suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize));if(suiteFailSize>0){
suiteTest.getModel().setStatus(Status.FAIL);
}
}
}
extent.flush();
}private voidinit() {//文件夹不存在的话进行创建
File reportDir= newFile(OUTPUT_FOLDER);if(!reportDir.exists()&& !reportDir .isDirectory()){
reportDir.mkdir();
}
ExtentHtmlReporter htmlReporter= new ExtentHtmlReporter(OUTPUT_FOLDER +FILE_NAME);
htmlReporter.config().setDocumentTitle("api自动化测试报告");
htmlReporter.config().setReportName("api自动化测试报告");
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);//htmlReporter.config().setTheme(Theme.STANDARD);
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}");
extent= newExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
}private voidbuildTestNodes(ExtentTest extenttest,IResultMap tests, Status status) {//存在父节点时,获取父节点的标签
String[] categories=new String[0];if(extenttest != null){
List categoryList =extenttest.getModel().getCategoryContext().getAll();
categories= newString[categoryList.size()];for(int index=0;index
categories[index]=categoryList.get(index).getName();
}
}
ExtentTest test;if (tests.size() > 0) {//调整用例排序,按时间排序
Set treeSet = new TreeSet(new Comparator() {
@Overridepublic intcompare(ITestResult o1, ITestResult o2) {return o1.getStartMillis()
}
});
treeSet.addAll(tests.getAllResults());for(ITestResult result : treeSet) {
Object[] parameters=result.getParameters();
String name="";//如果有参数,则使用参数的toString组合代替报告中的name//for(Object param:parameters){//name+=param.toString();//}//如果有参数只取第一个参数作test-name
for(int i=0;i
name= parameters[0].toString();
}if(name.length()>0){if(name.length()>100){
name= name.substring(0,100)+"...";
}
}else{
name=result.getMethod().getMethodName();
}if(extenttest==null){
test=extent.createTest(name);
}else{//作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。
test =extenttest.createNode(name).assignCategory(categories);
}//test.getModel().setDescription(description.toString());//test = extent.createTest(result.getMethod().getMethodName());
for(String group : result.getMethod().getGroups())
test.assignCategory(group);
List outputList =Reporter.getOutput(result);for(String output:outputList){//将用例的log输出报告中
test.debug(output);
}if (result.getThrowable() != null) {
test.log(status, result.getThrowable());
}else{
test.log(status,"Test " + status.toString().toLowerCase() + "ed");
}
test.getModel().setStartTime(getTime(result.getStartMillis()));
test.getModel().setEndTime(getTime(result.getEndMillis()));
}
}
}private Date getTime(longmillis) {
Calendar calendar=Calendar.getInstance();
calendar.setTimeInMillis(millis);returncalendar.getTime();
}
}