Java&Selenium&TestNG&ZTestReport|Java&Selenium&TestNG&ZTestReport 自动化测试并生成HTML自动化测试报告
一、摘要
本篇博文将介绍如何借助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 xmlSuites, List suites, String outputDirectory) {
List list = new ArrayList();
for (ISuite suite : suites) {
Map 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 listTestResult(IResultMap resultMap) {
Set results = resultMap.getAllResults();
return new ArrayList(results);
}private void sort(List list) {
Collections.sort(list, new Comparator() {
@Override
public int compare(ITestResult r1, ITestResult r2) {
if (r1.getStartMillis() > r2.getStartMillis()) {
return 1;
} else {
return -1;
}
}
});
}private void outputResult(List list) {
try {
List listInfo = new ArrayList();
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 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 result = new HashMap();
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 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 getLog() {
return log;
}public void setLog(List 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 【Java&Selenium&TestNG&ZTestReport|Java&Selenium&TestNG&ZTestReport 自动化测试并生成HTML自动化测试报告】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文件中声名
六拓展截图
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();
}
}
}
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 宋仲基&宋慧乔(我们不公布恋情,我们直接结婚。)
- 事件代理
- Java|Java OpenCV图像处理之SIFT角点检测详解
- java中如何实现重建二叉树
- 21天|21天|M&M《见识》04
- 数组常用方法一
- 【Hadoop踩雷】Mac下安装Hadoop3以及Java版本问题
- Java|Java基础——数组
- RxJava|RxJava 在Android项目中的使用(一)