testng生成自定義html報告

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

 

testng原生的或reportng的報告總有些不符合須要,嘗試生成自定義測試報告,
用到的依賴包:testng-6.9.9.jar,velocity-1.7.jar


1.定義一個DataBean,保存須要收集的數據前端

只定義部分數據,好比suite、testname、groups等好多數據還沒,須要用到的時候再加了java

 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.對須要特別處理的報告元素,好比測試周期、經過率apache

 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接口的方法進行排序的.app

(好像是能夠將getAllResults()轉成TreeSet排序?)ide

 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)ui

該方法在全部測試方法執行結束後被調用,經過遍歷 xmlSuites 和 suites 可以獲取全部測試方法的信息以及測試結果。outputDirectory 是默認的測試報表生成路徑,固然你能夠指定其餘路徑生成報表。this

 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文件,(要漂亮報告找前端。。。)spa

 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 }
相關文章
相關標籤/搜索