testng生成自定义html报告
2016-04-20 10:17
429 查看
testng原生的或reportng的报告总有些不符合需要,尝试生成自定义测试报告,
用到的依赖包:testng-6.9.9.jar,velocity-1.7.jar
1.定义一个DataBean,保存需要收集的数据
只定义部分数据,比如suite、testname、groups等好多数据还没,需要用到的时候再加了
2.对需要特别处理的报告元素,比如测试周期、通过率
3.测试方法排序,按测试方法执行时间排序
遍历 suites 得到的getAllResults()是一个set 集合,需要对数据进行排序
这里是将getAl
4000
lResults()转为list,实现Comparable接口的方法进行排序的.
(好像是可以将getAllResults()转成TreeSet排序?)
4.得到测试报告数据
package org.reporter.main;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.testng.IResultMap;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.Reporter;
public class ReporterData {
// 测试结果Set<ITestResult>转为list,再按执行时间排序 ,返回list
public List<ITestResult> sortByTime(Set<ITestResult> str) {
List<ITestResult> list = new ArrayList<ITestResult>();
for (ITestResult r : str) {
list.add(r);
}
Collections.sort(list);
return list;
}
public DataBean testContext(ITestContext context) {
// 测试结果汇总数据
DataBean data = new DataBean();
ReportUnits units = new ReportUnits();
IResultMap passedTests = context.getPassedTests();
IResultMap failedTests= context.getFailedTests();
IResultMap skipedTests = context.getSkippedTests();
//全部测试周期方法,包括beforetest,beforeclass,beforemethod,aftertest,afterclass,aftermethod
//IResultMap passedConfigurations =context.getPassedConfigurations();
//IResultMap failedConfigurations =context.getFailedConfigurations();
//IResultMap skipedConfigurations =context.getSkippedConfigurations();
Collection<ITestNGMethod> excludeTests = context.getExcludedMethods();
int passedTestsSize = passedTests.size();
int failedTestsSize = failedTests.size();
int skipedTestsSize = skipedTests.size();
int excludeTestsSize = excludeTests.size();
//所有测试结果的数量=测试pass+fail+skip的和,因为数据驱动一个测试方法有多次执行的可能,导致方法总数并不等于测试总数
int allTestsSize= passedTestsSize+failedTestsSize+skipedTestsSize;
data.setAllTestsSize(allTestsSize);
data.setPassedTestsSize(passedTestsSize);
data.setFailedTestsSize(failedTestsSize);
data.setSkippedTestsSize(skipedTestsSize);
data.setExcludeTestsSize(excludeTestsSize);
data.setTestsTime(units.getTestDuration(context));
data.setPassPercent(units.formatPercentage(passedTestsSize, allTestsSize));
data.setAllTestsMethod(context.getAllTestMethods());
data.setExcludeTestsMethod(context.getExcludedMethods());
return data;
}
public List<DataBean> testResults(IResultMap map, int status) {
// 测试结果详细数据
List<DataBean> list = new ArrayList<DataBean>();
ReportUnits units = new ReportUnits();
map.getAllResults().size();
for (ITestResult result : sortByTime(map.getAllResults())) {
DataBean data = new DataBean();
data.setTestName(result.getName());
data.setClassName(result.getTestClass().getName());
data.setDuration(units.formatDuration(result.getEndMillis()
- result.getStartMillis()));
data.setParams(units.getParams(result));
data.setDescription(result.getMethod().getDescription());
data.setOutput(Reporter.getOutput(result));
data.setDependMethod(units.getDependMethods(result));
data.setThrowable(result.getThrowable());
if (result.getThrowable() != null) {
data.setStackTrace(result.getThrowable().getStackTrace());
}
list.add(data);
}
return list;
}
}
5.生成测试报告,生成的测试报告是项目根目录下的report.html(要定制的话再改了)
使用 IReporter 监听器。IReporter 监听器只有一个方法需要实现。
void generateReport(java.util.List<XmlSuite> xmlSuites, java.util.List
<ISuite> suites, java.lang.String outputDirectory)
该方法在所有测试方法执行结束后被调用,通过遍历 xmlSuites 和 suites 能够获取所有测试方法的信息以及测试结果。outputDirectory 是默认的测试报表生成路径,当然你可以指定其他路径生成报表。
6.测试报告模板,文件后辍为vm,比如overview.vm,内容差不多就是一个html文件,(要漂亮报告找前端。。。)
7.测试报告,新建一个java项目,在测试类中添加监听器
@Listeners({com.reporter.main.GenerateReporter.class})
或者在testng.xml添加监听器
<listener class-name="com.reporter.main.GenerateReporter" />
用到的依赖包:testng-6.9.9.jar,velocity-1.7.jar
1.定义一个DataBean,保存需要收集的数据
只定义部分数据,比如suite、testname、groups等好多数据还没,需要用到的时候再加了
package com.reporter.main; import java.util.Collection; import java.util.List; import org.testng.ITestNGMethod; public class DataBean { private int excludeTestsSize; //未执行的test数量 private int passedTestsSize; //测试通过的数量 private int failedTestsSize; //测试失败的数量 private int skippedTestsSize; //测试跳过的数量 private int allTestsSize; //全部执行的测试的数量 private ITestNGMethod[] allTestsMethod; //全部执行的测试方法 private Collection<ITestNGMethod> excludeTestsMethod; //未执行的测试方法 private String testsTime; //测试耗时 private String passPercent; //测试通过率 private String testName; //测试方法名 private String className; //测试类名 private String duration; //单个测试周期 private String params; //测试用参数 private String description; //测试描述 private List<String> output; //Reporter Output private String dependMethod; //测试依赖方法 private Throwable throwable; //测试异常原因 private StackTraceElement[] stackTrace; // 异常堆栈信息 public int getExcludeTestsSize() { return excludeTestsSize; } public void setExcludeTestsSize(int excludeTestsSize) { this.excludeTestsSize = excludeTestsSize; } public int getPassedTestsSize() { return passedTestsSize; } public void setPassedTestsSize(int passedTestsSize) { this.passedTestsSize = passedTestsSize; } public int getFailedTestsSize() { return failedTestsSize; } public void setFailedTestsSize(int failedTestsSize) { this.failedTestsSize = failedTestsSize; } public int getSkippedTestsSize() { return skippedTestsSize; } public void setSkippedTestsSize(int skippedTestsSize) { this.skippedTestsSize = skippedTestsSize; } public int getAllTestsSize() { return allTestsSize; } public void setAllTestsSize(int allTestsSize) { this.allTestsSize = allTestsSize; } public String getPassPercent() { return passPercent; } public void setPassPercent(String passPercent) { this.passPercent = passPercent; } public String getTestName() { return testName; } public void setTestName(String testName) { this.testName = testName; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getDuration() { return duration; } public void setDuration(String duration) { this.duration = duration; } public String getParams() { return params; } public void setParams(String params) { this.params = params; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public List<String> getOutput() { return output; } public void setOutput(List<String> output) { this.output = output; } public String getDependMethod() { return dependMethod; } public void setDependMethod(String dependMethod) { this.dependMethod = dependMethod; } public Throwable getThrowable() { return throwable; } public void setThrowable(Throwable throwable2) { this.throwable = throwable2; } public StackTraceElement[] getStackTrace() { return stackTrace; } public void setStackTrace(StackTraceElement[] stackTrace) { this.stackTrace = stackTrace; } public void setTestsTime(String testsTime) { this.testsTime = testsTime; } public String getTestsTime() { return testsTime; } public void setAllTestsMethod(ITestNGMethod[] allTestsMethod) { this.allTestsMethod = allTestsMethod; } public ITestNGMethod[] getAllTestsMethod() { return allTestsMethod; } public void setExcludeTestsMethod(Collection<ITestNGMethod> excludeTestsMethod) { this.excludeTestsMethod = excludeTestsMethod; } public Collection<ITestNGMethod> getExcludeTestsMethod() { return excludeTestsMethod; } }
2.对需要特别处理的报告元素,比如测试周期、通过率
package com.reporter.main; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.Reporter; public class ReportUnits { private static final NumberFormat DURATION_FORMAT = new DecimalFormat("#0.000"); private static final NumberFormat PERCENTAGE_FORMAT = new DecimalFormat("#0.00%"); /** *测试消耗时长 *return 秒,保留3位小数 */ public String getTestDuration(ITestContext context){ long duration; duration=context.getEndDate().getTime()-context.getStartDate().getTime(); return formatDuration(duration); } public String formatDuration(long elapsed) { double seconds = (double) elapsed / 1000; return DURATION_FORMAT.format(seconds); } /** *测试通过率 *return 2.22%,保留2位小数 */ public String formatPercentage(int numerator, int denominator) { return PERCENTAGE_FORMAT.format(numerator / (double) denominator); } /** * 获取方法参数,以逗号分隔 * @param result * @return */ public String getParams(ITestResult result){ Object[] params = result.getParameters(); List<String> list = new ArrayList<String>(params.length); for (Object o:params){ list.add(renderArgument(o)); } return commaSeparate(list); } /** * 获取依赖的方法 * @param result * @return */ public String getDependMethods(ITestResult result){ String[] methods=result.getMethod().getMethodsDependedUpon(); return commaSeparate(Arrays.asList(methods)); } /** * 堆栈轨迹,暂不确定怎么做,放着先 * @param throwable * @return */ public String getCause(Throwable throwable){ StackTraceElement[] stackTrace=throwable.getStackTrace(); //堆栈轨迹 List<String> list = new ArrayList<String>(stackTrace.length); for (Object o:stackTrace){ list.add(renderArgument(o)); } return commaSeparate(list); } /** * 获取全部日志输出信息 * @return */ public List<String> getAllOutput(){ return Reporter.getOutput(); } /** * 按testresult获取日志输出信息 * @param result * @return */ public List<String> getTestOutput(ITestResult result){ return Reporter.getOutput(result); } /*将object 转换为String*/ private String renderArgument(Object argument) { if (argument == null) { return "null"; } else if (argument instanceof String) { return "\"" + argument + "\""; } else if (argument instanceof Character) { return "\'" + argument + "\'"; } else { return argument.toString(); } } /*将集合转换为以逗号分隔的字符串*/ private String commaSeparate(Collection<String> strings) { StringBuilder buffer = new StringBuilder(); Iterator<String> iterator = strings.iterator(); while (iterator.hasNext()) { String string = iterator.next(); buffer.append(string); if (iterator.hasNext()) { buffer.append(", "); } } return buffer.toString(); } }
3.测试方法排序,按测试方法执行时间排序
遍历 suites 得到的getAllResults()是一个set 集合,需要对数据进行排序
这里是将getAl
4000
lResults()转为list,实现Comparable接口的方法进行排序的.
(好像是可以将getAllResults()转成TreeSet排序?)
package com.reporter.main; import org.testng.ITestResult; public class TestResultSort implements Comparable<ITestResult> { private Long order; @Override public int compareTo(ITestResult arg0) { // TODO Auto-generated method stub return this.order.compareTo( arg0.getStartMillis());//按test开始时间排序 } }
4.得到测试报告数据
package org.reporter.main;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.testng.IResultMap;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.Reporter;
public class ReporterData {
// 测试结果Set<ITestResult>转为list,再按执行时间排序 ,返回list
public List<ITestResult> sortByTime(Set<ITestResult> str) {
List<ITestResult> list = new ArrayList<ITestResult>();
for (ITestResult r : str) {
list.add(r);
}
Collections.sort(list);
return list;
}
public DataBean testContext(ITestContext context) {
// 测试结果汇总数据
DataBean data = new DataBean();
ReportUnits units = new ReportUnits();
IResultMap passedTests = context.getPassedTests();
IResultMap failedTests= context.getFailedTests();
IResultMap skipedTests = context.getSkippedTests();
//全部测试周期方法,包括beforetest,beforeclass,beforemethod,aftertest,afterclass,aftermethod
//IResultMap passedConfigurations =context.getPassedConfigurations();
//IResultMap failedConfigurations =context.getFailedConfigurations();
//IResultMap skipedConfigurations =context.getSkippedConfigurations();
Collection<ITestNGMethod> excludeTests = context.getExcludedMethods();
int passedTestsSize = passedTests.size();
int failedTestsSize = failedTests.size();
int skipedTestsSize = skipedTests.size();
int excludeTestsSize = excludeTests.size();
//所有测试结果的数量=测试pass+fail+skip的和,因为数据驱动一个测试方法有多次执行的可能,导致方法总数并不等于测试总数
int allTestsSize= passedTestsSize+failedTestsSize+skipedTestsSize;
data.setAllTestsSize(allTestsSize);
data.setPassedTestsSize(passedTestsSize);
data.setFailedTestsSize(failedTestsSize);
data.setSkippedTestsSize(skipedTestsSize);
data.setExcludeTestsSize(excludeTestsSize);
data.setTestsTime(units.getTestDuration(context));
data.setPassPercent(units.formatPercentage(passedTestsSize, allTestsSize));
data.setAllTestsMethod(context.getAllTestMethods());
data.setExcludeTestsMethod(context.getExcludedMethods());
return data;
}
public List<DataBean> testResults(IResultMap map, int status) {
// 测试结果详细数据
List<DataBean> list = new ArrayList<DataBean>();
ReportUnits units = new ReportUnits();
map.getAllResults().size();
for (ITestResult result : sortByTime(map.getAllResults())) {
DataBean data = new DataBean();
data.setTestName(result.getName());
data.setClassName(result.getTestClass().getName());
data.setDuration(units.formatDuration(result.getEndMillis()
- result.getStartMillis()));
data.setParams(units.getParams(result));
data.setDescription(result.getMethod().getDescription());
data.setOutput(Reporter.getOutput(result));
data.setDependMethod(units.getDependMethods(result));
data.setThrowable(result.getThrowable());
if (result.getThrowable() != null) {
data.setStackTrace(result.getThrowable().getStackTrace());
}
list.add(data);
}
return list;
}
}
5.生成测试报告,生成的测试报告是项目根目录下的report.html(要定制的话再改了)
使用 IReporter 监听器。IReporter 监听器只有一个方法需要实现。
void generateReport(java.util.List<XmlSuite> xmlSuites, java.util.List
<ISuite> suites, java.lang.String outputDirectory)
该方法在所有测试方法执行结束后被调用,通过遍历 xmlSuites 和 suites 能够获取所有测试方法的信息以及测试结果。outputDirectory 是默认的测试报表生成路径,当然你可以指定其他路径生成报表。
package com.reporter.main; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.Writer; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.testng.IReporter; import org.testng.IResultMap; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.xml.XmlSuite; public class GenerateReporter implements IReporter { @Override public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) { // TODO Auto-generated method stub try { // 初始化并取得Velocity引擎 VelocityEngine ve = new VelocityEngine(); Properties p = new Properties(); //虽然不懂为什么这样设置,但结果是好的.可以用了 p.setProperty("resource.loader", "class"); p.setProperty("class.resource.loader.class","org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); ve.init(p); Template t = ve.getTemplate("com/reporter/VMmodel/overview.vm"); VelocityContext context = new VelocityContext(); for (ISuite suite : suites) { Map<String, ISuiteResult> suiteResults = suite.getResults(); for (ISuiteResult suiteResult : suiteResults.values()) { ReporterData data = new ReporterData(); ITestContext testContext = suiteResult.getTestContext(); // 把数据填入上下文 context.put("overView", data.testContext(testContext));//测试结果汇总信息 //ITestNGMethod[] allTests = testContext.getAllTestMethods();//所有的测试方法 //Collection<ITestNGMethod> excludeTests = testContext.getExcludedMethods();//未执行的测试方法 IResultMap passedTests = testContext.getPassedTests();//测试通过的测试方法 IResultMap failedTests = testContext.getFailedTests();//测试失败的测试方法 IResultMap skippedTests = testContext.getSkippedTests();//测试跳过的测试方法 context.put("pass", data.testResults(passedTests, ITestResult.SUCCESS)); context.put("fail", data.testResults(failedTests, ITestResult.FAILURE)); context.put("skip", data.testResults(skippedTests, ITestResult.FAILURE)); } } // 输出流 <span style="white-space:pre"> </span>//Writer writer = new BufferedWriter(new FileWriter("report.html")); <span style="white-space:pre"> </span>OutputStream out=new FileOutputStream("report.html"); <span style="white-space:pre"> </span>Writer writer = new BufferedWriter(new OutputStreamWriter(out,"utf-8"));//解决乱码问题 // 转换输出 t.merge(context, writer); //System.out.println(writer.toString()); writer.flush(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
6.测试报告模板,文件后辍为vm,比如overview.vm,内容差不多就是一个html文件,(要漂亮报告找前端。。。)
<?xml version="1.0" encoding="utf-8" ?> <head> <title>test</title> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <meta name="description" content="TestNG unit test results." /> </head> <body> <h1>Test</h1> <table border="1"> <tr> <th>OverView........</th> <th colspan="6" class="header suite"> <div > <a href="http://www.baidu.com">aaa</a> </div> </th> </tr> <tr class="columnHeadings"> <td> </td> <th>all</th> <th>excluded</th> <th>passed</th> <th>faild</th> <th>skipped</th> <th>duration(S)</th> <th>passration</th> <th>alltestMethod</th> <th>excluedMethod</th> </tr> <tr> <td>TestResult</td> <td>$overView.allTestsSize</td> <td>$overView.excludeTestsSize</td> <td>$overView.passedTestsSize</td> <td>$overView.failedTestsSize</td> <td>$overView.skippedTestsSize</td> <td>$overView.testsTime</td> <td>$overView.passPercent</td> <td> #foreach($p in $overView.allTestsMethod) $p<br/> #end </td> <td> #foreach($e in $overView.excludeTestsMethod) $e<br/> #end </td> </tr> </table> <br/><br/> <table border="1"> <tr> <th>PassTests.............</th> <th colspan="6" class="header suite"> <div > <a href="http://www.baidu.com">aaa</a> </div> </th> </tr> <tr class="columnHeadings"> <td> </td> <th>testName</th> <th>className</th> <th>duration</th> <th>params</th> <th>description</th> <th>output</th> <th>dependMethod</th> </tr> #foreach( $p in $pass) <tr> <td>$velocityCount</td> <td>${p.testName} #if(${p.description}) (${p.description}) #end</td> <td>$p.className</td> <td>$p.duration</td> <td>$!p.params</td> <td>$!p.description</td> <td> #foreach($o in $p.output) $o<br/> #end </td> <td>$p.dependMethod</td> <td>$!p.throwable</td> <td> #if($p.throwable ) #foreach($o in $p.stackTrace) $o<br/> #end #end </td> #end </tr> </table> <br/> <br/><br/> <table border="1"> <tr> <th>FailedTests...............</th> <th colspan="6" class="header suite"> <div > <a href="http://www.baidu.com">aaa</a> </div> </th> </tr> <tr class="columnHeadings"> <td> </td> <th>testName</th> <th>className</th> <th>duration</th> <th>params</th> <th>description</th> <th>output</th> <th>dependMethod</th> <th>throwable</th> <th>stackTrace</th> </tr> #foreach( $p in $fail) <tr> <td>$velocityCount</td> <td>$p.testName</td> <td>$p.className</td> <td>$p.duration</td> <td>$!p.params</td> <td>$!p.description</td> <td> #foreach($o in $p.output) $o<br/> #end </td> <td>$p.dependMethod</td> <td>$p.throwable</td> <td> #if($p.throwable ) #foreach($o in $p.stackTrace) $o<br/> #end #end </td> #end </tr> </table> <br/><br/> </body> </html>
7.测试报告,新建一个java项目,在测试类中添加监听器
@Listeners({com.reporter.main.GenerateReporter.class})
或者在testng.xml添加监听器
<listener class-name="com.reporter.main.GenerateReporter" />
import org.testng.Assert; import org.testng.Reporter; import org.testng.annotations.Listeners; import org.testng.annotations.Parameters; import org.testng.annotations.Test; @Listeners({com.reporter.main.GenerateReporter.class}) public class test { @Test public void a(){ Reporter.log("<a href='http://www.baidu.com' target='blank'>baidu.com</a>"); System.out.println("111"); } @Test(enabled=false,dependsOnMethods="a") @Parameters("param") public void b(String s){ Assert.assertEquals(s,"dataxml"); } @Test(enabled=true,dependsOnMethods="e") public void c(){ Assert.assertEquals(2,2); } @Test(description="测试方法 DDD") public void d() { Reporter.log("DDDDDDDDDD"); Reporter.log("AAAAAAAAAAAA"); System.out.println("Verify.verifyEquals(2,2)"); Assert.assertEquals(2,2); } @Test(description="98788",groups="test",invocationCount=1,dependsOnMethods="d") public void e() { Reporter.log("EEEEEEEEEEEEEEEEE"); Assert.assertEquals(1,2); System.out.println("Verify.verifyEquals(2,2)"); } }
相关文章推荐
- Android之使用Http协议实现文件上传功能
- mysql集群之MMM简单搭建
- 通晓网络测试常用命令
- Nodejs学习笔记之测试驱动
- 可以测试javascript运行效果的代码
- 使用php测试硬盘写入速度示例
- python 测试实现方法
- 如何测试端口通不通(四种方法)
- 举例详解PHP脚本的测试方法
- 使用Jasmine和Karma对AngularJS页面程序进行测试
- Php-Redis安装测试笔记
- mysql压力测试脚本实例
- JavaScript 组件之旅(四):测试 JavaScript 组件
- js简单网速测试方法完整实例
- Android触屏测试实例代码
- 解析libcurl在android下的移植、编译与测试
- 几个比较实用的JavaScript 测试及效验工具
- Java中对AtomicInteger和int值在多线程下递增操作的测试
- Python实现测试磁盘性能的方法
- python自动化测试实例解析