一、摘要

本篇博文将介绍如何借助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格式的报告

四、调用ZTestReport.java

方式一:在测试类添加监听

package testscript;
import org.apache.log4j.xml.DOMConfigurator;
import org.openqa.selenium.*;
import org.testng.Assert;
import org.testng.annotations.*;
import util.KeyActionsUtil;
import static util.KeyActionsUtil.*;
import java.util.List;
import static appmodule.MysqlService.linkToMysqlPage;
import static util.KeyBoardUtil.pressTabKey;
import static util.LogUtil.info;
import static pageobject.resourcemanagement.MySQLService.*;
import static util.ScrollBarUtil.scrolltoBottom;
import static util.WaitElementUtil.sleep;
// @Listeners({util.TestReport.class})
public class Test_Mysql { static {
DOMConfigurator.configure("log4j.xml");
}
@BeforeClass
public void setUp()throws Exception {
WebDriver driver = KeyActionsUtil.initBrowser("chrome");
linkToMysqlPage(driver, "yangdawei", "alex005x");
sleep(2000);
} @Test(priority = 0, description = "测试创建mysql数据库服务1CPU2G")
public void test_CreateMysqlInstance() throws Exception {
create_New_Instance_Button(driver).click();
info("点击创建实例按钮...");
sleep(1000);
info("等待3秒...");
instance_Name_in_Create_Instance_Dialog(driver).sendKeys("automationtest");
info("输入实例名:automationtesta");
sleep(1000);
info("等待3秒...");
//页面存在相同属性的元素,取所有放到list里,用序号操作
List<WebElement> radios = driver.findElements(By.className("el-radio-button__inner"));
radios.get(1).click();
sleep(1000);
info("选择数据库版本5.7...");
instance_Standard_in_Create_Instance_Dialog(driver).click();
info("点击实例规格...");
sleep(2000);
info("等待2秒...");
one_Core_two_GB(driver).click();
info("选择1CPU2GB...");
storage_Space_in_Create_Instance_Dialog(driver).clear();
info("清空存储空间字段...");
storage_Space_in_Create_Instance_Dialog(driver).sendKeys("1");
info("输入1G....");
scrolltoBottom(driver);
sleep(2000);
pressTabKey();
outsideaccess_Checkbox_in_Create_Instance_Dialog(driver).click();
info("选择外部链接...");
password_in_Create_Instance_Dialog(driver).sendKeys("111111");
info("输入密码111111...");
repassword_in_Create_Instance_Dialog(driver).sendKeys("111111");
info("确认密码111111...");
description_in_Create_Instance_Dialog(driver).sendKeys("automationtest");
info("描述信息输入automationtest");
sleep(2000);
submit_Button_in_Create_Instance_Dialog(driver).sendKeys(Keys.ENTER);
info("确认创建...");
sleep(2000);
refresh_Button(driver).click();
Assert.assertTrue(driver.getPageSource().contains("automationtest"));
Assert.assertTrue(driver.getPageSource().contains("创建中"));
}
@Test(priority = 1, description = "重启mysql服务")
public void test_RestartMysqlInstance()throws Exception {
operation_Button(driver).click();
info("点击列表里最后一列的...");
sleep(2000);
info("等待3秒...");
operation_Restart_Button(driver).click();
info("点击下拉菜单中的重启按钮...");
sleep(2000);
info("等待3秒...");
restart_Confirm_Button(driver).click();
info("点击确定按钮...");
sleep(2000);
info("等待3秒...");
Assert.assertTrue(driver.getPageSource().contains("重启请求成功"));
Assert.assertTrue(driver.getPageSource().contains("重启中"));
} @Test(priority = 2, description = "管理mysql服务页面")
public void test_Review_Basic_Mysql_Info()throws Exception{
operation_Button(driver).click();
info("点击列表里最后一列的...");
sleep(2000);
info("等待3秒...");
operation_Manage_Button(driver).click();
info("点击下拉菜单里的管理按钮...");
sleep(2000);
info("等待三秒");
assertString(driver,"基本信息");
}
@Test(priority = 3, description = "管理mysql服务页面")
public void test_Review_Mysql_Link()throws Exception{
database_Link_Tab(driver).click();
sleep(2000);
Assert.assertTrue(driver.getPageSource().contains("210.13.50.105"));
} @Test(priority = 4,description = "查看Mysql日志")
public void test_ReviewLog()throws Exception{
operation_Button(driver).click();
info("点击列表里最后一列的...");
sleep(2000);
info("等待3秒...");
operation_Log_Button(driver).click();
info("点击下拉菜单中的日志按钮...");
sleep(2000);
info("等待3秒...");
extend_Button_in_Log_Page(driver).click();
info("点击展开按钮...");
sleep(2000);
info("等待3秒...");
datefrom_in_Log_Page(driver).click();
info("点击第一个日期空间,弹出下拉...");
sleep(2000);
info("等待3秒...");
datefrom_by_Date_in_Log_Page(driver).clear();
datefrom_by_Date_in_Log_Page(driver).sendKeys("2018-09-01");
info("输入日期”2018-09-01");
sleep(2000);
info("等待3秒...");
datefrom_Sure_Button_in_Log_Page(driver).click();
info("点击确定按钮...");
sleep(2000);
info("等待3秒...");
search_Button_in_Log_Page(driver).click();
info("点击筛选按钮...");
sleep(2000);
info("等待3秒...");
Assert.assertTrue(driver.getPageSource().contains("Initializing database")); } @Test(priority = 5, description = "查看Mysql服务监控")
public void test_MonitorMysqlService()throws Exception{
operation_Button(driver).click();
info("点击列表里最后一列的...");
sleep(3000);
info("等待3秒...");
operation_Monitor_Button(driver).click();
info("点击下拉菜单里的监控按钮...");
sleep(3000);
info("等待3秒...");
} @Test(priority = 6, description = "释放mysql服务")
public void test_ReleaseMysqlService()throws Exception{
operation_Button(driver).click();
info("点击列表里最后一列的...");
sleep(3000);
info("等待3秒...");
operation_Release_Button(driver).click();
info("点击下拉菜单里的释放按钮...");
sleep(3000);
info("等待3秒...");
release_Confirm_Button(driver).click();
info("点击确定按钮...");
sleep(3000);
info("等待3秒...");
Assert.assertTrue(driver.getPageSource().contains("操作成功"));
Assert.assertTrue(driver.getPageSource().contains("删除中"));
} @AfterClass
public void afterMethod(){
driver.quit();
}
}

方式二:在testng.xml中添加监听

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite" preserve-order="true" verbose="2" allow-return-values="true">
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter" />
<listener class-name="org.uncommons.reportng.JUnitXMLReporter" />
<listener class-name="util.TestReport"/>
</listeners>
<suite-files>
<suite-file path="testng-spacemanagement.xml"/>
<suite-file path="testng-mysql.xml"/>
</suite-files>
</suite>

五、报告样式

Java&Selenium&TestNG&ZTestReport 自动化测试并生成HTML自动化测试报告的更多相关文章

  1. Python&Selenium&Unittest&BeautifuReport 自动化测试并生成HTML自动化测试报告

    一.摘要 本篇博文将介绍如何借助BeautifulReport和HTML模版,生成HTML测试报告的BeautifulReport 源码Clone地址为 https://github.com/Test ...

  2. java+Selenium+TestNg搭建自动化测试架构(1)实现代码和数据的分离

    1.主要介绍介绍Java+Selenium+POM的自动化测试框架的搭建,第一个首先实现代码和账号URL等信息的分离.第二点支持跨浏览器,通过读取配置文件的方式实现. 1)将账号URL等信息添加在pr ...

  3. java+Selenium+TestNg搭建自动化测试架构(3)实现POM(page+Object+modal)

    1.Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高测试用例 ...

  4. java+Selenium+TestNg搭建自动化测试架构(2)实现跨浏览器功能

    1.切换浏览器类:其中包含了切换浏览器的方法,以及关闭浏览器,设置等待时间,以及重写的断言方法 package com.rrx.framework; import java.io.IOExceptio ...

  5. Java+Selenium+Testng自动化测试学习(二)

    Java+Selenium+TestNG自动化测试框架整合 1.简化代码 封装一个定位元素的类,类型为ElementLocation package com.test; import org.open ...

  6. Java+Selenium+Testng自动化测试学习(四)— 报告

    自动化测试报告,在测试用例完成之后系统自动生成HTML报告 使用testng中的报告模板生成报告, 1.在TestSuit.xml文件中配置报告监听 2.运行xml文件 3.自动生成一个test-ou ...

  7. 基于Java+Selenium的WebUI自动化测试框架(六)---浏览器初始化

    本篇我们来讨论,如何写一个浏览器初始化的类.在写之前,先思考一下,我们需要一个什么样的初始化? 先来看看使用原生的Java + selenium是怎么做的.(以firefox为例) System.se ...

  8. Python HTMLTestRunner生成网页自动化测试报告时中文编码报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6

    1. 由于使用Python Selenium做网页自动化测试时,有截取网页上的中文信息保存到测试结果中,最终出现编码错误如下: File "D:/PycharmProjects/AutoTe ...

  9. python生成接口自动化测试报告模版

    1:准备html模版 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> &l ...

随机推荐

  1. C#实现排列、组合

    排列组合的概念 排列:从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排成一列,叫做从n个元素中取出m个元素的一个排列(Arrangement). 组合:从m个不同的元素中,任取n(n≤m)个元 ...

  2. 使用webpack搭建一个多页应用

     一.前言 最近需要为公司的活动写8个左右的移动端分享页面,有比较多的页面是公用的,如果用传统的方式来写的话,对于公用的代码抽取,css代码的压缩都是比较麻烦的,所以选择了webpack来搭建一个基本 ...

  3. Guava源码阅读-base-Charsets

    package com.google.common.base; 今天在找base包下的源码阅读时,看到了Charsets,肯定是定义字符集的类,本来就想简单的看一下.(部分内容摘抄自:http://b ...

  4. 通过JS动态追加标签,以父评论子评论为例

    以下代码前后端交互以Django模板语法为例 先来以伪代码来示意用法: HTML部分: JS动态插入部分代码: 运行之后我们来浏览器看检查打印的内容: 看插入前后打印结果我们可以得知 $title[0 ...

  5. [OpenCV] 图像亮度和对比度调整

    对比度调整的原理参考这篇博客 以下是代码实现: #include <iostream> #include "opencv2/core.hpp" #include &qu ...

  6. mysql 查询最佳实践

    (1)负向条件查询不能使用索引 select * from order where status!=0 and stauts!=1 not in/not exists都不是好习惯 (2)前导模糊查询不 ...

  7. c# base64及MD5工具类

    using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Lin ...

  8. Ubuntu 18.04修改默认源为国内源

    安装Ubuntu 18.04后,使用国外源太慢了,修改为国内源会快很多. 修改阿里源为Ubuntu 18.04默认的源 备份/etc/apt/sources.list 备份 cp /etc/apt/s ...

  9. Idea中maven的设置

    File->setting    输入MAVEN     看到右侧设置情况     Maven home directory 熟路本地moven 仓库目录:D:/springboot/apach ...

  10. Python爬虫详解

    Python爬虫详解 Python 之 Urllib库的基本使用 Python中requests库使用方法详解 Beautifulsoup模块基础用法详解 selenium模块基础用法详解 re(正则 ...