一、摘要
本篇博文将介绍如何借助ZTestReport和HTML模版,生成HTML测试报告的ZTestReport 源码Clone地址为 https://github.com/zhangfei19841004/ztest,其中ZTestReport.java
和其template是我们需要的关键。
二、ZTestReport.java
根据我的需要,在源码基础上进行了稍微修改,其中几个注释的地方需要注意,将其集成进自己的自动化框架时需要做相应的修改
package util;
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.*;
import java.util.regex.Matcher;
public class TestReport implements IReporter {
private long currentTime = System.currentTimeMillis();
private SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
private Date date = new Date(currentTime);
private String reportdate = formatter.format(date);
// 定义生成测试报告的路径和文件名,为兼容Windows和Linux此处使用File.separator代替分隔符
private String path = System.getProperty("user.dir")+File.separator+reportdate+".html";
// 定义html样式模板所在路径
private String templatePath = System.getProperty("user.dir")+File.separator+"template";
private int testsPass = 0;
private int testsFail = 0;
private int testsSkip = 0;
private String beginTime;
private long totalTime;
private String name = "PaaS平台自动化测试";
/**
public TestReport(){
long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
Date date = new Date(currentTime);
name = formatter.format(date);
}
public TestReport(String name){
this.name = name;
if(this.name==null){
long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年-MM月-dd日-HH时mm分ss秒");
Date date = new Date(currentTime);
this.name = formatter.format(date);
}
}
*/
@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) {
if (r1.getStartMillis() > r2.getStartMillis()) {
return 1;
} else {
return -1;
}
}
});
}
private void outputResult(List<ITestResult> list) {
try {
List<ReportInfo> listInfo = new ArrayList<ReportInfo>();
int index = 0;
for (ITestResult result : list) {
String tn = result.getTestContext().getCurrentXmlTest().getParameter("testCase");
if(index==0){
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
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(tn);
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);
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(templatePath);
BufferedWriter output = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(new File(path)),"UTF-8"));
template = template.replaceFirst("\\$\\{resultData\\}", Matcher.quoteReplacement(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 path) {
File file = new File(path);
InputStream is = null;
StringBuffer sb = new StringBuffer();
try {
is = new FileInputStream(file);
int index = 0;
byte[] b = new byte[1024];
while ((index = is.read(b)) != -1) {
sb.append(new String(b, 0, index));
}
return sb.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
三、template
template文件是和ZTestReport.java一起使用的,他可以将TestNG的测试结果按照template的样式转换成HTML格式的报告
四 创建监听类
package com.test.listener;
import com.hand.utils.ScreenShot;
import com.test.BaseTest;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.WebDriver;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import org.testng.annotations.Listeners;
@Slf4j
public class TestLogListener extends TestListenerAdapter {
@Override
public void onStart(ITestContext iTestContext) {
super.onStart( iTestContext );
log.info( String.format( "====================%s测试开始====================", iTestContext.getName() ) );
}
@Override
public void onTestStart(ITestResult iTestResult) {
super.onTestStart( iTestResult );
log.info( String.format( "========%s.%s测试开始========", iTestResult.getInstanceName(), iTestResult.getName()) );
}
@Override
public void onTestSuccess(ITestResult iTestResult) {
super.onTestSuccess( iTestResult );
log.info( String.format( "========%s.%s测试通过========", iTestResult.getInstanceName(), iTestResult.getName()) );
}
@Override
public void onTestFailure(ITestResult iTestResult) {
WebDriver driver = BaseTest.driverBase.getDriver();
System.out.print( "report_driver_fail:" + driver );
super.onTestFailure( iTestResult );
log.error( String.format( "========%s.%s测试失败,失败原因如下:\n%s========", iTestResult.getInstanceName(), iTestResult.getName(), iTestResult.getThrowable() ));
// 失败截图
ScreenShot.takeScreenShot( driver,iTestResult);
}
@Override
public void onTestSkipped(ITestResult iTestResult) {
super.onTestSkipped( iTestResult );
log.info( String.format( "========%s.%s跳过测试========", iTestResult.getInstanceName(), iTestResult.getName()) );
}
@Override
public void onFinish(ITestContext iTestContext) {
super.onFinish( iTestContext );
log.info( String.format( "====================%s测试结束====================", iTestContext.getName() ) );
}
}
五设置监听
两种方法:1在代码中设置
//固定写法 你的监听类(继承TestListenerAdapter的类)
@Listeners({ com.example.MyListener.class, com.example.MyMethodInterceptor.class })
public class MyTest {//测试类
// ...
}
二:在xml文件中声名
<listeners>
<listener class-name="com.test.listener.TestLogListener"/>
<listener class-name="com.test.listener.TestReportListener"/>
</listeners>
六拓展截图
package com.hand.utils;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.testng.ITestResult;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ScreenShot{
private static String screenShotDirPath = System.getProperty("user.dir") + File.separator +"target" + File.separator + "test-output" + File.separator + "errorScreenShot";
public static void takeScreenShot(WebDriver driver,ITestResult iTestResult) {
Object currentClass = iTestResult.getInstance();// 获取当前 Object 类型的测试类
//获取包名
String packageName = currentClass.getClass().getPackage().getName();
System.out.println("packageName : " + packageName);
/* //根据获得的类名,去掉包名
String currentClassName = currentClass.toString().replaceAll(packageName,"");
System.out.println("currentClassName : " + currentClassName);*/
String currentClassName = currentClass.toString();
//正则匹配
Pattern pattern = Pattern.compile(packageName+".(.*?)@");//此处为正则表达式
Matcher matcher = pattern.matcher(currentClassName);//去匹配正则表达式
while (matcher.find()) {
currentClassName = matcher.group(1);
System.out.println("currentClassName:" + currentClassName);
}
// System.out.println("出错的类为:" + currentClassStr);
File screenShotDir = new File(screenShotDirPath);
if (!screenShotDir.exists() && !screenShotDir.isDirectory()) {
screenShotDir.mkdirs();
}
//SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年-MM月-dd日-HH时-mm分-ss秒SSS");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH点mm分ss秒");
String time = simpleDateFormat.format(new Date());
try {
File source_file = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); // 屏幕截图
//System.out.println("出错的截图命名为:" + currentClass.toString() + ".png");
FileUtils.copyFile(source_file, new File(screenShotDirPath + File.separator + currentClassName + time + ".png")); // 另存截图
} catch (IOException e) {
e.printStackTrace();
}
}
}
网友评论