背景
Testng报告是否可以自定义,后面通过查找资料便有了如下自定义报告,testng中提供很多接口,如果需要改造成自己报告只要实现他们的接口即可,以下是根据自己想法实现如下自定义testng报告,如果大家感兴趣,可以根据自己需求修改。也可以把这些数据存储到数据库,之后通过一定规则即可展示出来
注意中间{ echarts.min.js }需要到网上找下放到对应目录即可。
参考代码:
代码语言:javascript复制import org.testng.*;import org.testng.annotations.Test;import org.testng.reporters.HtmlHelper;import org.testng.xml.XmlSuite;
import java.io.File;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;import java.text.SimpleDateFormat;import java.util.*;
/** * @author 李文 * @Title: thReporter * @Description: 自定义测试报告 * @date 2019/3/15 / 9:45 */publicclassThReporterimplementsIReporter{
/** * 获取系统信息 */privatestaticProperties sysProperty = System.getProperties(); /** * 报告路径 */privateString reportPath;/** * 接口类型 */privateStringMobile_phone= "SOA层自动化";/** * 版本号 */privateString package_name = "2.9.0";/** *//** * 通过 */privatestaticintPassed= 0;/** * 失败 */privatestaticintFailed= 0;/** * 跳过 */privatestaticintSkipped= 0;/** * 用例总共合计 */privatestaticintCountNum= 0;/** * 通过结果 */privatestaticStringPssResuTmp, PassgetName;/** * 开始时间 */privatestaticStringStartDate;/** * 结束时间 */privatestaticStringEndDate;/** * 描述 */privatestaticString description;/** * 客户端类型 */privatestaticString clienttype;
/** * 拼接报告数据 */staticStringBuilder sb1 = newStringBuilder();
@Overridepublicvoid generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
File htmlReportDir = newFile("test-output/Test-report");if(!htmlReportDir.exists()) { htmlReportDir.mkdirs();}String reportName = formateDate() ".html"; reportPath = htmlReportDir "/" reportName;File report = newFile(htmlReportDir, reportName);if(report.exists()) {try{ report.createNewFile();} catch(IOException e) { e.printStackTrace();}}
StringBuffer sb = newStringBuffer();String title = "SOA层自动化";/**浏览器兼容型添加 http://www.ichartjs.com/ichart.latest.min.js */ sb.append("<!Doctype >n<head><meta http-equiv=Content-Type content="text/html;charset=utf-8"><script src='echarts.min.js'></script><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta content=always name=referrer><title>UI自动化测试报告</title>").append(HtmlHelper.getCssString(".")).append("</head><body style="background-color:#FAEBD7;">n").append("<h2><p align='center'>").append(title).append("</p></h2>n").append("<table cellspacing='0' cellpadding='0' border='1' width='90%'>").append("<tr><th>接口类型</th><th>版本号</th><th><font color="#00FF00">通过数</th><th><font color="#FF0000">失败数</th><th><font color="#ADFF2F">跳过</th><th>用例数 </th><th>类数 </th><th>开始时间 </th><th>结束时间 </th></tr>n");String res = sb.toString();try{Files.write((Paths.get(reportPath)), res.getBytes("utf-8"));} catch(IOException e) { e.printStackTrace();}/** * 控制台信息打印 */ThReporter.getprintinfotestng(suites);
sb1.append("<td>" Mobile_phone "</td><td>" package_name "</td>"); sb1.append("<td>" Passed "</td><td>" Failed "</td><td>" Skipped "</td><td>" (Passed Failed Skipped) "</td><td>" CountNum "</td><td>" StartDate "</td><td>" EndDate "</td>n"); sb1.append("</table><br/>").append("<pre><div id='canvasDiv'></div></pre>").append("<pre style="text-align:center"><div id="newmain" style="width: 1000px;height:300px; padding-left:50px "></div></pre>").append("<table cellspacing='0' cellpadding='0' border='0' width='90%'>").append("<tr><th>" "执行用例数:" (Passed Failed Skipped) "</th></tr>").append("</table>").append("<tbody style="word-wrap:break-word;font-weight:bold;" align="center"><h2>详 情</h2>").append("<table cellspacing='0' cellpadding='0' border='1' width='90%'>");
sb1.append("<tr><th>序列号 </th><th>失 败</th><th>用例类名</th><th>详情信息</th><th>接口中文名字与验证点</th></tr>n");/**详细失败数*/ThReporter.getFailedpped(suites);
sb1.append("<tr><th>序列号 </th><th>通 过</th><th>用例类名</th><th>详情信息</th><th>接口中文名字与验证点</th></tr>n");/**详细通过数*/ThReporter.getPassed(suites);
sb1.append("<tr><th>序列号 </th><th>跳 过</th><th>用例类名</th><th>详情信息</th><th>接口中文名字与验证点</th></tr>n");/** * 详细跳过数 */ThReporter.getskipped(suites);
sb1.append("</table><br/>");
代码中插入图代码
代码语言:javascript复制sb1.append("</tbody></table><a href="#top">SOA层自动化</a></div><script type="text/javascript">n" " // 基于准备好的dom,初始化echarts实例n" " var myChart = echarts.init(document.getElementById('newmain'));n" "n" " // 指定图表的配置项和数据n" " var option = {n" " title : {n" " text: 'SOA层自动化',n" " subtext: '接口自动化',n" " x:'center'n" " },n" " tooltip : {n" " trigger: 'item',n" " formatter: "{a} <br/>{b} : {c} ({d}%)"n" " },n" " legend: {n" " text: 'SOA',n" " x : 'center',n" " y : 'bottom',n" " subtext: '333',n" " // left: 'top',n" " data:['不通过','通过','跳过']n" "n" " },n" " toolbox: {n" " show : true,n" " feature : {n" " mark : {show: true},n" " dataView : {show: true, readOnly: false},n" " magicType : {n" " show: true,n" " type: ['pie', 'funnel']n" " },n" " restore : {show: true},n" " saveAsImage : {show: true}n" " }n" " },n" " calculable : true,n" " series : [n" " {n" " name:'SOA层自动化',n" " type:'pie',n" " radius : [30, 110],n" " center : ['75%', '50%'],n" " roseType : 'area',n" " data:[n" " {value:" Failed ",name:'不通过',itemStyle:{color:'#EE0000'}},n" " {value:" Passed ",name:'通过',itemStyle:{color:'#7CFC00'}},n" " {value:" Skipped ",name:'跳过',itemStyle:{color:'#EE9572'}}n" " ],n" " itemStyle: {n" " emphasis: {n" " shadowBlur: 10,n" " shadowOffsetX: 0,n" " shadowColor: 'rgba(0, 0, 0, 0.5)'n" " },n" " normal: {n" " label: {n" " show: true,n" " formatter: '{b} : {c} ({d}%)'n" " },n" " labelLine: {show: true}n" " }n" " }n" " }n" " ,{n" " name:'SOA层自动化',n" " type:'pie',n" " radius : [20, 110],n" " center : ['25%', '50%'],n" " roseType : 'radius',n" " label: {n" " normal: {n" " show: truen" " },n" " emphasis: {n" " show: truen" " },n" " },n" " lableLine: {n" " normal: {n" " show: falsen" " },n" " emphasis: {n" " show: truen" " }n" " },n" " data:[{value:" Failed ",name:'不通过',itemStyle:{color:'#EE0000'}},n" " {value:'" Passed "',name:'通过',itemStyle:{color:'#7CFC00'}},n" " {value:" Skipped ",name:'跳过',itemStyle:{color:'#EE9572'}}],n" " itemStyle: {n" " emphasis: {n" " shadowBlur: 10,n" " shadowOffsetX: 0,n" " shadowColor: 'rgba(0, 0, 0, 0.5)'n" " },n" " normal: {n" " label: {n" " show: true,n" " formatter: '{b} : {c} ({d}%)'n" " },n" " labelLine: {show: true}n" " }n" " }n" " }n" "n" " ]n" " };n" " myChart.setOption(option);n" "n" "</script></body></html>n");
String res1 = sb1.toString();try{Files.write((Paths.get(reportPath)), res1.getBytes("UTF-8"), StandardOpenOption.APPEND);} catch(IOException e) { e.printStackTrace();}}
测试类结束控制台显示
代码语言:javascript复制/** * 控制台信息打印 */privatestaticvoid getprintinfotestng(List<ISuite> suites) {SimpleDateFormat sf = newSimpleDateFormat("yyyy-MM-dd-HH mm-ss");
for(ISuite suite : suites) {Map<String, ISuiteResult> tests = suite.getResults();for(ISuiteResult r : tests.values()) {ITestContext overview = r.getTestContext();LogUtil.info("suite: " overview.getName());LogUtil.info("Stard Time: " sf.format(overview.getStartDate()));StartDate= sf.format(overview.getStartDate());LogUtil.info("End Time: " sf.format(overview.getEndDate()));EndDate= sf.format(overview.getEndDate());CountNum= overview.getAllTestMethods().length;LogUtil.info("all methods num : " overview.getAllTestMethods().length);
//passedPassed= overview.getPassedTests().size();LogUtil.info("passed: " overview.getPassedTests().size());Set<ITestResult> passedSet = overview.getPassedTests().getAllResults();
for(ITestResult p : passedSet) { description = p.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Test.class).description();LogUtil.info("class: " p.getTestClass().getName() " | method: " description);}
//failedFailed= overview.getFailedTests().size();LogUtil.info("failed: " overview.getFailedTests().size());Set<ITestResult> failedSet = overview.getFailedTests().getAllResults();for(ITestResult f : failedSet) {LogUtil.info("class: " f.getTestClass().getName() " | method: " f.getName() " | error: " f.getThrowable());}
//skippedSkipped= overview.getSkippedTests().size();LogUtil.info("skipped: " overview.getSkippedTests().size());Set<ITestResult> skippedSet = overview.getSkippedTests().getAllResults();for(ITestResult s : skippedSet) {LogUtil.info("---- " s.getName());LogUtil.info(s.getThrowable() "");}LogUtil.info("==================================");}
}}
跳过方法编写
代码语言:javascript复制/** * 详细跳过数 */publicstaticvoid getskipped(List<ISuite> suites) {/**详细跳过数*/for(ISuite suite : suites) {Map<String, ISuiteResult> tests = suite.getResults();for(ISuiteResult r : tests.values()) {ITestContext overview = r.getTestContext();CountNum= overview.getAllTestMethods().length;Set<ITestResult> skippedSet = overview.getSkippedTests().getAllResults();int i = 0;for(ITestResult s : skippedSet) { description = s.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Test.class).description(); sb1.append("<tr><td>" i "</td><td><font color="FF9966"> 跳过</font></td><td>" s.getName() "</td><td>" "接口名字:" s.getThrowable() "</td><td>验证点:" description "</td>"); i ;}}}}
失败方法编写
代码语言:javascript复制/** * 详细失败数 */publicstaticvoid getFailedpped(List<ISuite> suites) {for(ISuite suite : suites) {Map<String, ISuiteResult> tests = suite.getResults();for(ISuiteResult r : tests.values()) {ITestContext overview = r.getTestContext();CountNum= overview.getAllTestMethods().length;int i = 0;Set<ITestResult> failedSet = overview.getFailedTests().getAllResults();for(ITestResult f : failedSet) { description = f.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Test.class).description();LogUtil.info("class: " f.getTestClass().getName() " | method: " f.getName() " | error: " f.getThrowable()); sb1.append("<tr><td>" i "</td><td><font color="FF0000"> 失败</font></td><td>" f.getTestClass().getName() "</td><td>" "测试方法名: " f.getName() " 失败详情: " f.getThrowable() "</td><td>验证点:" description "</td>"); i ;}}}
通过方法编写
代码语言:javascript复制/** * 详细通过数 */publicstaticvoid getPassed(List<ISuite> suites) {for(ISuite suite : suites) {Map<String, ISuiteResult> tests = suite.getResults();for(ISuiteResult r : tests.values()) {ITestContext overview = r.getTestContext();CountNum= overview.getAllTestMethods().length;Set<ITestResult> passedSet = overview.getPassedTests().getAllResults();
int i = 0;for(ITestResult p : passedSet) {LogUtil.info("class: " p.getTestClass().getName() " | method: " p.getName());PssResuTmp= p.getTestClass().getName();PassgetName= p.getName(); description = p.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Test.class).description();/**获取客户端类型如果安卓、pc版本*/ clienttype = p.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Test.class).testName(); sb1.append("<tr><td>" i "</td><td><font color="#00FF00"> 通 过</font></td><td>" PssResuTmp "</td><td>" "接口名字:" PassgetName "</td><td>验证点:" description "</td>"); i ;}}}}
日期格式化方法
代码语言:javascript复制/** * 日期格式化 * * @return date */publicstaticString formateDate() {SimpleDateFormat sf = newSimpleDateFormat("yyyy-MM-dd-HH-mm-ss");Calendar cal = Calendar.getInstance();Date date = cal.getTime();return sf.format(date);}
/** * 日期格式化 * * @return date */privatestaticString formatDate(long date) {SimpleDateFormat formatter = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");return formatter.format(date);}
监听写好后,通过xml配置即可。
代码语言:javascript复制<suitename="First suite"verbose="1"><listeners><listenerclass-name="com.threport.ThReporter"/></listeners>
<testname="接口测试报告"><packages><packagename="执行的包名"/></packages></test></suite>
在这里引用屈原《离骚》"路漫漫其修远兮,吾将上下而求索"。