码迷,mamicode.com
首页 > Web开发 > 详细

testng生成自定义html报告

时间:2018-04-20 16:14:00      阅读:391      评论:0      收藏:0      [点我收藏+]

标签:其他   字符串   dwr   sort   rtm   .text   load   map   buffered   

转自:https://blog.csdn.net/kdslkd/article/details/51198433

 

testng原生的或reportng的报告总有些不符合需要,尝试生成自定义测试报告,
用到的依赖包:testng-6.9.9.jar,velocity-1.7.jar


1.定义一个DataBean,保存需要收集的数据

只定义部分数据,比如suite、testname、groups等好多数据还没,需要用到的时候再加了

  1 package com.reporter.main;
  2 
  3 import java.util.Collection;
  4 import java.util.List;
  5 
  6 import org.testng.ITestNGMethod;
  7 
  8 public class DataBean {
  9     private int excludeTestsSize; //未执行的test数量
 10     private int passedTestsSize; //测试通过的数量
 11     private int failedTestsSize; //测试失败的数量
 12     private int skippedTestsSize; //测试跳过的数量
 13     private int allTestsSize; //全部执行的测试的数量
 14     private ITestNGMethod[] allTestsMethod; //全部执行的测试方法
 15     private Collection<ITestNGMethod> excludeTestsMethod; //未执行的测试方法
 16     private String testsTime; //测试耗时
 17     private String passPercent; //测试通过率
 18     private String testName; //测试方法名
 19     private String className; //测试类名
 20     private String duration; //单个测试周期
 21     private String params; //测试用参数
 22     private String description; //测试描述
 23     private List<String> output; //Reporter Output
 24     private String dependMethod; //测试依赖方法
 25     private Throwable throwable; //测试异常原因
 26     private StackTraceElement[] stackTrace; // 异常堆栈信息
 27 
 28     public int getExcludeTestsSize() {
 29         return excludeTestsSize;
 30     }
 31 
 32     public void setExcludeTestsSize(int excludeTestsSize) {
 33         this.excludeTestsSize = excludeTestsSize;
 34     }
 35 
 36     public int getPassedTestsSize() {
 37         return passedTestsSize;
 38     }
 39 
 40     public void setPassedTestsSize(int passedTestsSize) {
 41         this.passedTestsSize = passedTestsSize;
 42     }
 43 
 44     public int getFailedTestsSize() {
 45         return failedTestsSize;
 46     }
 47 
 48     public void setFailedTestsSize(int failedTestsSize) {
 49         this.failedTestsSize = failedTestsSize;
 50     }
 51 
 52     public int getSkippedTestsSize() {
 53         return skippedTestsSize;
 54     }
 55 
 56     public void setSkippedTestsSize(int skippedTestsSize) {
 57         this.skippedTestsSize = skippedTestsSize;
 58     }
 59 
 60     public int getAllTestsSize() {
 61         return allTestsSize;
 62     }
 63 
 64     public void setAllTestsSize(int allTestsSize) {
 65         this.allTestsSize = allTestsSize;
 66     }
 67 
 68     public String getPassPercent() {
 69         return passPercent;
 70     }
 71 
 72     public void setPassPercent(String passPercent) {
 73         this.passPercent = passPercent;
 74     }
 75 
 76     public String getTestName() {
 77         return testName;
 78     }
 79 
 80     public void setTestName(String testName) {
 81         this.testName = testName;
 82     }
 83 
 84     public String getClassName() {
 85         return className;
 86     }
 87 
 88     public void setClassName(String className) {
 89         this.className = className;
 90     }
 91 
 92     public String getDuration() {
 93         return duration;
 94     }
 95 
 96     public void setDuration(String duration) {
 97         this.duration = duration;
 98     }
 99 
100     public String getParams() {
101         return params;
102     }
103 
104     public void setParams(String params) {
105         this.params = params;
106     }
107 
108     public String getDescription() {
109         return description;
110     }
111 
112     public void setDescription(String description) {
113         this.description = description;
114     }
115 
116     public List<String> getOutput() {
117         return output;
118     }
119 
120     public void setOutput(List<String> output) {
121         this.output = output;
122     }
123 
124     public String getDependMethod() {
125         return dependMethod;
126     }
127 
128     public void setDependMethod(String dependMethod) {
129         this.dependMethod = dependMethod;
130     }
131 
132     public Throwable getThrowable() {
133         return throwable;
134     }
135 
136     public void setThrowable(Throwable throwable2) {
137         this.throwable = throwable2;
138     }
139 
140     public StackTraceElement[] getStackTrace() {
141         return stackTrace;
142     }
143 
144     public void setStackTrace(StackTraceElement[] stackTrace) {
145         this.stackTrace = stackTrace;
146     }
147 
148     public void setTestsTime(String testsTime) {
149         this.testsTime = testsTime;
150     }
151 
152     public String getTestsTime() {
153         return testsTime;
154     }
155 
156     public void setAllTestsMethod(ITestNGMethod[] allTestsMethod) {
157         this.allTestsMethod = allTestsMethod;
158     }
159 
160     public ITestNGMethod[] getAllTestsMethod() {
161         return allTestsMethod;
162     }
163 
164     public void setExcludeTestsMethod(Collection<ITestNGMethod> excludeTestsMethod) {
165         this.excludeTestsMethod = excludeTestsMethod;
166     }
167 
168     public Collection<ITestNGMethod> getExcludeTestsMethod() {
169         return excludeTestsMethod;
170     }
171 
172 }

2.对需要特别处理的报告元素,比如测试周期、通过率

  1 package com.reporter.main;
  2 
  3 import java.text.DecimalFormat;
  4 import java.text.NumberFormat;
  5 import java.util.ArrayList;
  6 import java.util.Arrays;
  7 import java.util.Collection;
  8 import java.util.Iterator;
  9 import java.util.List;
 10 import org.testng.ITestContext;
 11 import org.testng.ITestResult;
 12 import org.testng.Reporter;
 13 
 14 public class ReportUnits {
 15     private static final NumberFormat DURATION_FORMAT = new DecimalFormat("#0.000");
 16     private static final NumberFormat PERCENTAGE_FORMAT = new DecimalFormat("#0.00%");
 17     /**
 18      *测试消耗时长 
 19      *return 秒,保留3位小数
 20      */
 21     public String getTestDuration(ITestContext context){
 22         long duration;
 23         duration=context.getEndDate().getTime()-context.getStartDate().getTime();
 24         return formatDuration(duration);
 25     }
 26     
 27     public String formatDuration(long elapsed)
 28     {
 29         double seconds = (double) elapsed / 1000;
 30         return DURATION_FORMAT.format(seconds);
 31     }
 32     /**
 33      *测试通过率 
 34      *return 2.22%,保留2位小数
 35      */
 36     public String formatPercentage(int numerator, int denominator)
 37     {
 38         return PERCENTAGE_FORMAT.format(numerator / (double) denominator);
 39     }
 40     
 41     /**
 42      * 获取方法参数,以逗号分隔
 43      * @param result
 44      * @return
 45      */
 46     public String getParams(ITestResult result){
 47         Object[] params = result.getParameters();
 48         List<String> list = new ArrayList<String>(params.length);
 49         for (Object o:params){
 50             list.add(renderArgument(o));
 51         }        
 52         return  commaSeparate(list);        
 53     }
 54     /**
 55      * 获取依赖的方法
 56      * @param result
 57      * @return
 58      */
 59     public String getDependMethods(ITestResult result){
 60         String[] methods=result.getMethod().getMethodsDependedUpon();
 61         return commaSeparate(Arrays.asList(methods));
 62     }
 63     /**
 64      * 堆栈轨迹,暂不确定怎么做,放着先
 65      * @param throwable
 66      * @return
 67      */
 68     public String getCause(Throwable throwable){        
 69         StackTraceElement[] stackTrace=throwable.getStackTrace(); //堆栈轨迹
 70         List<String> list = new ArrayList<String>(stackTrace.length);
 71         for (Object o:stackTrace){
 72             list.add(renderArgument(o));
 73         }        
 74         return  commaSeparate(list);        
 75     }
 76     /**
 77      * 获取全部日志输出信息
 78      * @return
 79      */
 80     public List<String> getAllOutput(){
 81         return Reporter.getOutput();
 82     }
 83     
 84     /**
 85      * 按testresult获取日志输出信息
 86      * @param result
 87      * @return
 88      */
 89     public List<String> getTestOutput(ITestResult result){
 90         return Reporter.getOutput(result);
 91     }
 92     
 93 
 94     /*将object 转换为String*/
 95     private String renderArgument(Object argument)
 96     {
 97         if (argument == null)
 98         {
 99             return "null";
100         }
101         else if (argument instanceof String)
102         {
103             return "\"" + argument + "\"";
104         }
105         else if (argument instanceof Character)
106         {
107             return "\‘" + argument + "\‘";
108         }
109         else
110         {
111             return argument.toString();
112         }
113     }
114     /*将集合转换为以逗号分隔的字符串*/
115     private String commaSeparate(Collection<String> strings)
116     {
117         StringBuilder buffer = new StringBuilder();
118         Iterator<String> iterator = strings.iterator();
119         while (iterator.hasNext())
120         {
121             String string = iterator.next();
122             buffer.append(string);
123             if (iterator.hasNext())
124             {
125                 buffer.append(", ");
126             }
127         }
128         return buffer.toString();
129     }
130 }

3.测试方法排序,按测试方法执行时间排序
遍历 suites 得到的getAllResults()是一个set 集合,需要对数据进行排序
这里是将getAllResults()转为list,实现Comparable接口的方法进行排序的.

(好像是可以将getAllResults()转成TreeSet排序?)

 1 package com.reporter.main;
 2 
 3 import org.testng.ITestResult;
 4 
 5 public class TestResultSort implements Comparable<ITestResult> {
 6     private Long order;
 7     @Override
 8     public int compareTo(ITestResult arg0) {
 9         // TODO Auto-generated method stub
10         return this.order.compareTo( arg0.getStartMillis());//按test开始时间排序
11     }
12 
13 }

4.得到测试报告数据

 1 package org.reporter.main;
 2 
 3 
 4 import java.util.ArrayList;
 5 import java.util.Collection;
 6 import java.util.Collections;
 7 import java.util.List;
 8 import java.util.Set;
 9 
10 
11 import org.testng.IResultMap;
12 import org.testng.ITestContext;
13 import org.testng.ITestNGMethod;
14 import org.testng.ITestResult;
15 import org.testng.Reporter;
16 
17 
18 
19 
20 public class ReporterData {
21     // 测试结果Set<ITestResult>转为list,再按执行时间排序 ,返回list
22     public List<ITestResult> sortByTime(Set<ITestResult> str) {
23         List<ITestResult> list = new ArrayList<ITestResult>();
24         for (ITestResult r : str) {
25             list.add(r);
26         }
27         Collections.sort(list);
28         return list;
29 
30 
31     }
32     
33     public DataBean testContext(ITestContext context) {
34         // 测试结果汇总数据
35         DataBean data = new DataBean();
36         ReportUnits units = new ReportUnits();
37         IResultMap passedTests = context.getPassedTests();
38         IResultMap failedTests= context.getFailedTests();
39         IResultMap skipedTests = context.getSkippedTests();    
40         //全部测试周期方法,包括beforetest,beforeclass,beforemethod,aftertest,afterclass,aftermethod
41         //IResultMap passedConfigurations =context.getPassedConfigurations(); 
42         //IResultMap failedConfigurations =context.getFailedConfigurations();
43         //IResultMap skipedConfigurations =context.getSkippedConfigurations();
44         Collection<ITestNGMethod> excludeTests = context.getExcludedMethods();        
45         
46         int passedTestsSize = passedTests.size();
47         int failedTestsSize = failedTests.size();
48         int skipedTestsSize = skipedTests.size();
49         int excludeTestsSize = excludeTests.size();
50         //所有测试结果的数量=测试pass+fail+skip的和,因为数据驱动一个测试方法有多次执行的可能,导致方法总数并不等于测试总数
51         int allTestsSize= passedTestsSize+failedTestsSize+skipedTestsSize;
52         data.setAllTestsSize(allTestsSize);
53         data.setPassedTestsSize(passedTestsSize);
54         data.setFailedTestsSize(failedTestsSize);
55         data.setSkippedTestsSize(skipedTestsSize);
56         data.setExcludeTestsSize(excludeTestsSize);
57         data.setTestsTime(units.getTestDuration(context));        
58         data.setPassPercent(units.formatPercentage(passedTestsSize, allTestsSize));        
59         data.setAllTestsMethod(context.getAllTestMethods());
60         data.setExcludeTestsMethod(context.getExcludedMethods());
61         
62         return data;
63 
64 
65     }
66 
67 
68     public List<DataBean> testResults(IResultMap map, int status) {
69         // 测试结果详细数据
70         List<DataBean> list = new ArrayList<DataBean>();
71         ReportUnits units = new ReportUnits();
72         map.getAllResults().size();
73         for (ITestResult result : sortByTime(map.getAllResults())) {
74             DataBean data = new DataBean();
75             data.setTestName(result.getName());
76             data.setClassName(result.getTestClass().getName());
77             data.setDuration(units.formatDuration(result.getEndMillis()
78                     - result.getStartMillis()));
79             data.setParams(units.getParams(result));
80             data.setDescription(result.getMethod().getDescription());
81             data.setOutput(Reporter.getOutput(result));
82             data.setDependMethod(units.getDependMethods(result));
83             data.setThrowable(result.getThrowable());
84             if (result.getThrowable() != null) {
85                 data.setStackTrace(result.getThrowable().getStackTrace());
86             }
87             list.add(data);
88         }
89         return list;
90     }
91 
92 }

5.生成测试报告,生成的测试报告是项目根目录下的report.html(要定制的话再改了)
使用 IReporter 监听器。IReporter 监听器只有一个方法需要实现。
void generateReport(java.util.List<XmlSuite> xmlSuites, java.util.List
<ISuite> suites, java.lang.String outputDirectory)

该方法在所有测试方法执行结束后被调用,通过遍历 xmlSuites 和 suites 能够获取所有测试方法的信息以及测试结果。outputDirectory 是默认的测试报表生成路径,当然你可以指定其他路径生成报表。

 1 package com.reporter.main;
 2 
 3 import java.io.BufferedWriter;
 4 import java.io.FileWriter;
 5 import java.io.Writer;
 6 import java.util.List;
 7 import java.util.Map;
 8 import java.util.Properties;
 9 import org.apache.velocity.Template;
10 import org.apache.velocity.VelocityContext;
11 import org.apache.velocity.app.VelocityEngine;
12 import org.testng.IReporter;
13 import org.testng.IResultMap;
14 import org.testng.ISuite;
15 import org.testng.ISuiteResult;
16 import org.testng.ITestContext;
17 import org.testng.ITestResult;
18 import org.testng.xml.XmlSuite;
19 
20 public class GenerateReporter implements IReporter {
21     @Override
22     public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites,
23             String outputDirectory) {
24         // TODO Auto-generated method stub            
25         try {
26             // 初始化并取得Velocity引擎    
27             VelocityEngine ve = new VelocityEngine();
28             Properties p = new Properties();
29             //虽然不懂为什么这样设置,但结果是好的.可以用了
30             p.setProperty("resource.loader", "class");             
31             p.setProperty("class.resource.loader.class","org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
32             ve.init(p);    
33             Template t = ve.getTemplate("com/reporter/VMmodel/overview.vm");
34             VelocityContext context = new VelocityContext();
35 
36             for (ISuite suite : suites) {
37                 Map<String, ISuiteResult> suiteResults = suite.getResults();
38                 for (ISuiteResult suiteResult : suiteResults.values()) {
39                     ReporterData data = new ReporterData();                    
40                     ITestContext testContext = suiteResult.getTestContext();
41                     // 把数据填入上下文
42                     context.put("overView", data.testContext(testContext));//测试结果汇总信息
43                     //ITestNGMethod[] allTests = testContext.getAllTestMethods();//所有的测试方法 
44                     //Collection<ITestNGMethod> excludeTests = testContext.getExcludedMethods();//未执行的测试方法
45                     IResultMap passedTests = testContext.getPassedTests();//测试通过的测试方法
46                     IResultMap failedTests = testContext.getFailedTests();//测试失败的测试方法
47                     IResultMap skippedTests = testContext.getSkippedTests();//测试跳过的测试方法
48        
49                     context.put("pass", data.testResults(passedTests, ITestResult.SUCCESS));
50                     context.put("fail", data.testResults(failedTests, ITestResult.FAILURE));
51                     context.put("skip", data.testResults(skippedTests, ITestResult.FAILURE));
52                     
53                     
54                         
55                 }
56             }
57             // 输出流
58 <span style="white-space:pre">            </span>//Writer writer = new BufferedWriter(new FileWriter("report.html"));
59 <span style="white-space:pre">            </span>OutputStream out=new FileOutputStream("report.html");
60 <span style="white-space:pre">            </span>Writer writer = new BufferedWriter(new OutputStreamWriter(out,"utf-8"));//解决乱码问题
61             // 转换输出
62             t.merge(context, writer);
63             //System.out.println(writer.toString());
64             writer.flush();
65         } catch (Exception e) {
66             // TODO Auto-generated catch block
67             e.printStackTrace();
68         }
69     }
70     
71 
72 }

6.测试报告模板,文件后辍为vm,比如overview.vm,内容差不多就是一个html文件,(要漂亮报告找前端。。。)

  1 <?xml version="1.0" encoding="utf-8" ?>
  2 
  3 <head>
  4   <title>test</title>
  5   <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  6   <meta name="description" content="TestNG unit test results." />
  7   
  8 </head>
  9 <body>
 10 
 11 <h1>Test</h1>
 12 <table border="1">
 13   <tr>
 14   <th>OverView........</th>
 15     <th colspan="6" class="header suite">
 16       <div > 
 17         <a href="http://www.baidu.com">aaa</a>               
 18       </div>
 19     </th>
 20   </tr>
 21   <tr class="columnHeadings">
 22     <td> </td>
 23     <th>all</th>
 24     <th>excluded</th>
 25     <th>passed</th>
 26     <th>faild</th>
 27     <th>skipped</th>
 28     <th>duration(S)</th>
 29     <th>passration</th>
 30     <th>alltestMethod</th>
 31     <th>excluedMethod</th>
 32   </tr>
 33   
 34   <tr>
 35   <td>TestResult</td>     
 36     <td>$overView.allTestsSize</td> 
 37     <td>$overView.excludeTestsSize</td> 
 38     <td>$overView.passedTestsSize</td> 
 39     <td>$overView.failedTestsSize</td> 
 40     <td>$overView.skippedTestsSize</td> 
 41     <td>$overView.testsTime</td>     
 42     <td>$overView.passPercent</td>    
 43     <td>
 44     #foreach($p in $overView.allTestsMethod)
 45         $p<br/>
 46     #end
 47     </td> 
 48     <td>
 49     #foreach($e in $overView.excludeTestsMethod)
 50         $e<br/>
 51     #end
 52     </td>     
 53 </tr>  
 54 </table>
 55 <br/><br/>
 56 <table border="1">
 57   <tr>
 58   <th>PassTests.............</th>
 59     <th colspan="6" class="header suite">
 60       <div > 
 61         <a href="http://www.baidu.com">aaa</a>               
 62       </div>
 63     </th>
 64   </tr>
 65   <tr class="columnHeadings">
 66     <td> </td>
 67     <th>testName</th>
 68     <th>className</th>
 69     <th>duration</th>
 70     <th>params</th>
 71     <th>description</th>
 72     <th>output</th>
 73     <th>dependMethod</th>
 74   </tr>
 75   
 76   #foreach( $p in $pass)
 77       <tr>   
 78       <td>$velocityCount</td>
 79       <td>${p.testName}
 80       #if(${p.description})
 81        (${p.description})
 82        #end</td>  
 83       <td>$p.className</td> 
 84       <td>$p.duration</td> 
 85       <td>$!p.params</td> 
 86       <td>$!p.description</td> 
 87       <td>
 88       #foreach($o in $p.output)
 89       $o<br/>
 90       #end
 91       </td>
 92       <td>$p.dependMethod</td>
 93         <td>$!p.throwable</td>
 94         <td>
 95        #if($p.throwable )
 96           #foreach($o in $p.stackTrace)
 97               $o<br/>
 98           #end
 99       #end
100       </td>  
101   #end  
102 </tr> 
103  
104 </table>
105 <br/>
106 
107 
108 <br/><br/>
109 
110 <table border="1">
111   <tr>
112   <th>FailedTests...............</th>
113     <th colspan="6" class="header suite">
114       <div > 
115         <a href="http://www.baidu.com">aaa</a>               
116       </div>
117     </th>
118   </tr>
119   <tr class="columnHeadings">
120     <td> </td>
121     <th>testName</th>
122     <th>className</th>
123     <th>duration</th>
124     <th>params</th>
125     <th>description</th>
126     <th>output</th>
127     <th>dependMethod</th>
128     <th>throwable</th>
129     <th>stackTrace</th>
130   </tr>
131   
132   #foreach( $p in $fail)
133   <tr>   
134   <td>$velocityCount</td>
135   <td>$p.testName</td>  
136   <td>$p.className</td> 
137   <td>$p.duration</td> 
138   <td>$!p.params</td> 
139   <td>$!p.description</td> 
140   <td>
141   #foreach($o in $p.output)
142   $o<br/>
143   #end
144   </td>
145   <td>$p.dependMethod</td>
146   <td>$p.throwable</td>
147     <td>
148    #if($p.throwable )
149   #foreach($o in $p.stackTrace)
150   $o<br/>
151   #end
152   #end
153   </td>  
154   #end
155 </tr> 
156  
157 
158 </table>
159 
160 <br/><br/>
161 
162 
163 
164 </body>
165 </html>

7.测试报告,新建一个java项目,在测试类中添加监听器
@Listeners({com.reporter.main.GenerateReporter.class})
或者在testng.xml添加监听器

<listener class-name="com.reporter.main.GenerateReporter" />

 1 import org.testng.Assert;
 2 import org.testng.Reporter;
 3 import org.testng.annotations.Listeners;
 4 import org.testng.annotations.Parameters;
 5 import org.testng.annotations.Test;
 6 
 7 @Listeners({com.reporter.main.GenerateReporter.class})
 8 public class test {
 9     @Test
10     public void a(){
11         Reporter.log("<a href=‘http://www.baidu.com‘ target=‘blank‘>baidu.com</a>");
12         System.out.println("111");
13     }
14     @Test(enabled=false,dependsOnMethods="a")
15     @Parameters("param")
16     public void b(String s){
17         Assert.assertEquals(s,"dataxml");
18         
19     }
20     @Test(enabled=true,dependsOnMethods="e")
21     public void c(){        
22         Assert.assertEquals(2,2);
23     }
24     @Test(description="测试方法 DDD")
25     public void d() {
26         Reporter.log("DDDDDDDDDD");
27         Reporter.log("AAAAAAAAAAAA");
28         System.out.println("Verify.verifyEquals(2,2)");
29          Assert.assertEquals(2,2);
30     }
31     @Test(description="98788",groups="test",invocationCount=1,dependsOnMethods="d")
32     public void e() {
33         Reporter.log("EEEEEEEEEEEEEEEEE");
34         Assert.assertEquals(1,2);
35         System.out.println("Verify.verifyEquals(2,2)");
36     }
37 }

 

testng生成自定义html报告

标签:其他   字符串   dwr   sort   rtm   .text   load   map   buffered   

原文地址:https://www.cnblogs.com/cheese320/p/8890929.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!