extentsreport testng美化报告生成
一:主要内容
- 优化testng测试报告,使用extentsreport
- 解决extentsreport打开后加载不出来样式的问题
二:报告效果
先上图,看下testng extentsreport报告展示的效果,支持用例总数统计、成功用例数统计、失败用例数统计、用例失败具体日志信息在页面中也有展示
正常用例
异常用例
三:配置extentsreport过程
先给大家看下我的工程大概情况
下面我们就按照上面的图里的步骤来进行描述:
1.导入pom依赖
新建一个maven工程或者在你的已有工程中,点击pom.xml,将如下跟testng报告有关的依赖添加进去
<!--testng-->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>compile</scope>
</dependency>
<!--extentsreport-->
<dependency>
<groupId>com.relevantcodes</groupId>
<artifactId>extentreports</artifactId>
<version>2.41.1</version>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>testng-extentsreport</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.0.6</version>
</dependency>
2.新建ExtentTestNGIReporterListener监听类,尤其注意红色标注栏的代码不能少,是解决extentsreport报告加载不出来页面的关键所在
package com.testng.report; import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.ResourceCDN;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.model.TestAttribute;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.aventstack.extentreports.reporter.configuration.ChartLocation;
import com.aventstack.extentreports.reporter.configuration.Theme;
import org.testng.*;
import org.testng.xml.XmlSuite; import java.io.File;
import java.util.*; /**
* @创建人 yumeiling
* @创建时间 2019/6/20
* @描述 testng报告类
*/
public class ExtentTestNGIReporterListener implements IReporter {
//生成的路径以及文件名
private static final String OUTPUT_FOLDER = "test-output/";
private static final String FILE_NAME = "index.html"; private ExtentReports extent; @Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
init();
boolean createSuiteNode = false;
if (suites.size() > 1) {
createSuiteNode = true;
}
for (ISuite suite : suites) {
Map<String, ISuiteResult> 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);
}
} }
// for (String s : Reporter.getOutput()) {
// extent.setTestRunnerOutput(s);
// } extent.flush();
} private void init() {
//文件夹不存在的话进行创建
File reportDir = new File(OUTPUT_FOLDER);
if (!reportDir.exists() && !reportDir.isDirectory()) {
reportDir.mkdir();
}
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
// 设置静态文件的DNS
// 解决cdn.rawgit.com访问不了的情况
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS); htmlReporter.config().setDocumentTitle("testng自动化测试报告");
htmlReporter.config().setReportName("testng自动化测试报告");
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
htmlReporter.config().setTheme(Theme.STANDARD);
htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}");
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
} private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) {
//存在父节点时,获取父节点的标签
String[] categories = new String[0];
if (extenttest != null) {
List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();
categories = new String[categoryList.size()];
for (int index = 0; index < categoryList.size(); index++) {
categories[index] = categoryList.get(index).getName();
}
} ExtentTest test; if (tests.size() > 0) {
//调整用例排序,按时间排序
Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() {
@Override
public int compare(ITestResult o1, ITestResult o2) {
return o1.getStartMillis() < o2.getStartMillis() ? -1 : 1;
}
});
treeSet.addAll(tests.getAllResults());
for (ITestResult result : treeSet) {
Object[] parameters = result.getParameters();
String name = "";
//如果有参数,则使用参数的toString组合代替报告中的name
for (Object param : parameters) {
name += param.toString();
}
if (name.length() > 0) {
if (name.length() > 50) {
name = name.substring(0, 49) + "...";
}
} 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<String> 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(long millis) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
return calendar.getTime();
}
}
3.新建一个testng的测试用例类,或者你已经有了,那就用你自己的testng类就可以了,为了让报告中有正常、异常用例的效果,所以测试用例中故意造了两个会引起异常的用例。
package com.testng.report; import org.testng.Assert;
import org.testng.Reporter;
import org.testng.annotations.Test; /**
* @创建人 yumeiling
* @创建时间 2019/6/20
* @描述
*/
public class Demo {
@Test
public void testA(){
Reporter.log("这是testng美化报告的一个正常测试用例");
Assert.assertEquals(1,1);
}
@Test
public void testB(){
Assert.assertEquals("test","Result");
}
@Test
public void testC(){
Assert.assertEquals(true,true);
}
@Test
public void testD(){
Reporter.log("这是testng美化报告的一个失败测试用例");
throw new RuntimeException("这是为了让报告存在异常用例,自己抛出的异常");
}
}
4.配置testng.xml文件,记住要加上监听配置,然后运行testng.xml文件,就可以在指定的路径下看到输出的报告文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="testng reporter报告套件">
<test name="测试模块">
<classes>
<class name="com.testng.report.Demo"/>
</classes>
</test>
<listeners>
<listener class-name="com.testng.report.ExtentTestNGIReporterListener" />
</listeners>
</suite>
运行testng.xml后,在工程路径下可以看到生成了一个test-output文件夹,里面有个index.html文件,浏览器打开后就是我们上面二中看到的那幅图的效果了,怎么样很方便吧。
博文均为原创文章,转载请注明出处,感谢!
extentsreport testng美化报告生成的更多相关文章
- 使用extentreports美化报告
无意之间在整理testng 报告输出的文档时,发现一个美化testng的报告的插件,感觉确实“漂亮”,但是还不确定是否实用,案例来自官方网站自己添了一些内容,更改了存放路径,本地目前已确定可正常运行, ...
- ITTC数据挖掘平台介绍(五) 数据导入导出向导和报告生成
一. 前言 经过了一个多月的努力,软件系统又添加了不少新功能.这些功能包括非常实用的数据导入导出,对触摸进行优化的画布和画笔工具,以及对一些智能分析的报告生成模块等.进一步加强了平台系统级的功能. 马 ...
- Oracle AWRDD报告生成和性能分析
我写的SQL调优专栏:https://blog.csdn.net/u014427391/article/category/8679315 对于局部的,比如某个页面列表sql,我们可以使用Oracle的 ...
- Oracle ADDM报告生成和性能分析
我写的SQL调优专栏:https://blog.csdn.net/u014427391/article/category/8679315 对于局部的,比如某个页面列表sql,我们可以使用Oracle的 ...
- Oracle AWRSQRPT报告生成和性能分析
我写的SQL调优专栏:https://blog.csdn.net/u014427391/article/category/8679315 对于局部的,比如某个页面列表sql,我们可以使用Oracle的 ...
- Oracle ASH报告生成和性能分析
我写的SQL调优专栏:https://blog.csdn.net/u014427391/article/category/8679315 对于局部的,比如某个页面列表sql,我们可以使用Oracle的 ...
- Oracle AWR报告生成和性能分析
目录 一.AWE报告生成步骤 1.1 工具选择 1.2 自动创建快照 1.3 手工创建快照 1.4 生成AWR报告 二.AWR报告分析 2.1 AWR之DB Time 2.2 AWR之load_pro ...
- [转]oracle awr报告生成和分析
转自:http://blog.csdn.net/cuker919/article/details/8767328 最近由于数据库cpu占用非常高,导致VCS常常自动切换,引起很多问题. 最近学习一下数 ...
- ddt 接口示范以及报告生成html案例
1.数据构造获取我就不写了直接以test_data=[ ] 构造一个简单数据建模.实际你从哪里获取根据情况excel也好yaml也罢 2.用例套件处理,报告生成处理 import ddtimport ...
随机推荐
- Http的简单介绍
之前写过一篇使用HttpListener作为简单的HTTP服务器,后面实际项目中就用到了,测试发现,在Win7下如果不是以管理员权限运行程序,使用HttpListener是会出错了. 所以就很好奇HT ...
- 权限(rwx)对于目录与文件的意义
1-权限对于目录的意义 首先要明白的是目录主要的内容是记录文件名列表和子目录列表,而不是实际存放数据的地方. r权限:拥有此权限表示可以读取目录结构列表,也就是说可以查看目录下的文件名和子目录名,注意 ...
- 禁止ios10双指缩放
document.addEventListener('gesturestart', function(event) { event.preventDefault(); });
- textarea 限制输入字数
一般情况下很多人限制textarea的输入字数会使用 onkeyup 或 onchange事件,但是这两种事件都带有明显的不足. onkeyup 事件只能监听键盘事件,而对于用户的粘贴毫无办法:而on ...
- HackIM web关writeup
Web100 访问页面将看到下面的错误 在burp里使用request / response查看有没有什么不正常的地方.如下图所示,在返回的数据包里被设置了两次不同的PHPSESSID. 如果我把PH ...
- aiomysql实现对数据库异步读取
有一个库叫做aiomysql,这是一个基于asyncio和pymysql的库.至于为什么可以在tornado中使用,是因为高版本tornado的底层使用了asyncio. import asyncio ...
- linux 用户及文件权限管理
Linux 是一个可以实现多用户登陆的操作系统,比如“李雷”和“韩梅梅”都可以同时登陆同一台主机,他们共享一些主机的资源,但他们也分别有自己的用户空间,用于存放各自的文件.但实际上他们的文件都是放在同 ...
- PAT Basic 1010 一元多项式求导 (25 分)
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串.字符串由若干单词和若干空格组成,其中单词是由英文字母(大小 ...
- Summer training round2 #5 (Training #21)
A:正着DFS一次处理出每个节点有多少个优先级比他低的(包括自己)作为值v[i] 求A B 再反着DFS求优先级比自己高的求C #include <bits/stdc++.h> #incl ...
- target_link_libraries每次能连接1个???
target_link_libraries(usb-1.0)target_link_libraries(cyusb)