java testng 中使用 BeautifulReport 测试报告模板
程序员文章站
2022-04-10 23:32:58
...
文章目录
我在做 java 的 WebUI 自动化测试的时候,会要求生成测试报告,用 testng 自带的测试报告,样式太丑了,因此需要使用其他的模板样式,这里我考虑使用 BeautifulReport 报告模板样式,其实对于 python 来说可以直接 pip BeautifulReport 来做,当然这里我介绍的是 java 项目
这里展示一下 BeautifulReport 模板样式
第一步:maven 配置依赖
WebUI 项目中其实 selenium 依赖 testng 依赖都应该有,下面这个 extentreports 是用来做定制模板的依赖
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.0.7</version>
</dependency>
第二步:编写测试报告监听器类
我在项目下src/test/java/com/abcnull/listener
添加了一个测试报告监听器类 TestReportListener,它继承自 testng 依赖包中的 IReporter。TestReportListener 中其实没用到太多 extentreports 依赖中的 API,只有 Gson 类来自 extentreports 依赖中,基本还是靠着第三步中写好的 BeautifulReport 型式的 html 模板,代码如下:
package com.abcnull.listener;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.testng.*;
import org.testng.xml.XmlSuite;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author abcnull
* @version 1.0.0
* @date 2020/1/26
*/
public class TestReportListener implements IReporter {
// 日期格式化
private static Date date = new Date();
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd,HH点mm分ss秒");
private static String reportdate = simpleDateFormat.format(date);
private static String getReportName = "自动化测试报告-" + reportdate;
// 定义html模板所在路径
private String templatePath = this.getClass().getResource("/").getPath() + "report/template.html";
// 定义报告生成的路径
private String reportDirPath = System.getProperty("user.dir") + File.separator + "target" + File.separator + "test-output" + File.separator + "report";
private String reportPath = reportDirPath + File.separator + getReportName + ".html";
private String name = "DemoTest";
private int testsPass;
private int testsFail;
private int testsSkip;
private String beginTime;
private long totalTime;
private String project = "WebUI自动化测试报告";
@Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
List<ITestResult> list = new ArrayList<ITestResult>();
for (ISuite suite : suites) {
Map<String, ISuiteResult> suiteResults = suite.getResults();
for (ISuiteResult suiteResult : suiteResults.values()) {
ITestContext testContext = suiteResult.getTestContext();
IResultMap passedTests = testContext.getPassedTests();
testsPass = testsPass + passedTests.size();
IResultMap failedTests = testContext.getFailedTests();
testsFail = testsFail + failedTests.size();
IResultMap skippedTests = testContext.getSkippedTests();
testsSkip = testsSkip + skippedTests.size();
IResultMap failedConfig = testContext.getFailedConfigurations();
list.addAll(this.listTestResult(passedTests));
list.addAll(this.listTestResult(failedTests));
list.addAll(this.listTestResult(skippedTests));
list.addAll(this.listTestResult(failedConfig));
}
}
this.sort(list);
this.outputResult(list);
}
private ArrayList<ITestResult> listTestResult(IResultMap resultMap) {
Set<ITestResult> results = resultMap.getAllResults();
return new ArrayList<ITestResult>(results);
}
private void sort(List<ITestResult> list) {
Collections.sort(list, new Comparator<ITestResult>() {
@Override
public int compare(ITestResult r1, ITestResult r2) {
return r1.getStartMillis() < r2.getStartMillis() ? -1 : 1;
}
});
}
public long getTime() {
return totalTime;
}
private void outputResult(List<ITestResult> list) {
try {
List<ReportInfo> listInfo = new ArrayList<ReportInfo>();
int index = 0;
for (ITestResult result : list) {
String testName = result.getTestContext().getCurrentXmlTest().getName();
if (index == 0) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSSS");
beginTime = formatter.format(new Date(result.getStartMillis()));
index++;
}
long spendTime = result.getEndMillis() - result.getStartMillis();
totalTime += spendTime;
String status = this.getStatus(result.getStatus());
List<String> log = Reporter.getOutput(result);
for (int i = 0; i < log.size(); i++) {
log.set(i, log.get(i).replaceAll("\"", "\\\\\""));
}
Throwable throwable = result.getThrowable();
if (throwable != null) {
log.add(throwable.toString().replaceAll("\"", "\\\\\""));
StackTraceElement[] st = throwable.getStackTrace();
for (StackTraceElement stackTraceElement : st) {
log.add((" " + stackTraceElement).replaceAll("\"", "\\\\\""));
}
}
ReportInfo info = new ReportInfo();
info.setName(testName);
info.setSpendTime(spendTime + "ms");
info.setStatus(status);
info.setClassName(result.getInstanceName());
info.setMethodName(result.getName());
info.setDescription(result.getMethod().getDescription());
info.setLog(log);
listInfo.add(info);
}
Map<String, Object> result = new HashMap<String, Object>();
//result.put("testName", name);
System.out.println("aaa@qq.com#= 运行时间为" + totalTime + "################");
result.put("testName", this.project);
result.put("testPass", testsPass);
result.put("testFail", testsFail);
result.put("testSkip", testsSkip);
result.put("testAll", testsPass + testsFail + testsSkip);
result.put("beginTime", beginTime);
result.put("totalTime", totalTime + "ms");
result.put("testResult", listInfo);
Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
String template = this.read(reportDirPath, templatePath);
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(reportPath)), "UTF-8"));
template = template.replace("${resultData}", gson.toJson(result));
output.write(template);
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private String getStatus(int status) {
String statusString = null;
switch (status) {
case 1:
statusString = "成功";
break;
case 2:
statusString = "失败";
break;
case 3:
statusString = "跳过";
break;
default:
break;
}
return statusString;
}
public static class ReportInfo {
private String name;
private String className;
private String methodName;
private String description;
private String spendTime;
private String status;
private List<String> log;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getSpendTime() {
return spendTime;
}
public void setSpendTime(String spendTime) {
this.spendTime = spendTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List<String> getLog() {
return log;
}
public void setLog(List<String> log) {
this.log = log;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
private String read(String reportDirPath, String templatePath) {
//文件夹不存在时级联创建目录
File reportDir = new File(reportDirPath);
if (!reportDir.exists() && !reportDir.isDirectory()) {
reportDir.mkdirs();
}
File templateFile = new File(templatePath);
InputStream inputStream = null;
StringBuffer stringBuffer = new StringBuffer();
try {
inputStream = new FileInputStream(templateFile);
int index = 0;
byte[] b = new byte[1024];
while ((index = inputStream.read(b)) != -1) {
stringBuffer.append(new String(b, 0, index));
}
return stringBuffer.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
当然这个监听器代码中很多地方可以做定制化修改
第三步:testng.xml 配置测试报告监听器
在 testng.xml 中配置上监听器如下:
<listeners>
<listener class-name="com.abcnull.listener.TestReportListener"/>
</listeners>
第四步:项目添加 html 测试报告模板
在src/test/resources/report
中添加了 template.html 测试报告模板,模板使用了在线版 bootstrap,完整 html 文件会在此博文中上传资源附件,不用担心下载此附件消耗 0 积分!
这个 template.html 模板会在测试报告监听器中指定用什么报告模板
第五步:查看测试报告
由于项目是 maven 项目,测试完用例之后我们可以在target/test-output/report
下查看到新产生的 html 测试报告
当然这个报告生成的路径也是可以在测试报告监听器中指定的