使用ExtentReport生成漂亮的测试报告

Posted heyuling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用ExtentReport生成漂亮的测试报告相关的知识,希望对你有一定的参考价值。

1.引入依赖

 1         <dependency>
 2             <groupId>com.relevantcodes</groupId>
 3             <artifactId>extentreports</artifactId>
 4             <version>2.41.1</version>
 5         </dependency>
 6 
 7         <dependency>
 8             <groupId>com.vimalselvam</groupId>
 9             <artifactId>testng-extentsreport</artifactId>
10             <version>1.3.1</version>
11         </dependency>
12 
13         <dependency>
14             <groupId>com.aventstack</groupId>
15             <artifactId>extentreports</artifactId>
16             <version>3.0.6</version>
17         </dependency>    

2.编写测试

 1 public class Demo1 {
 2     @Test
 3     public void test1() {
 4         Assert.assertEquals("aaa", "aaa");
 5     }
 6     @Test
 7     public void test2() {
 8         Assert.assertEquals(1, 2);
 9     }
10     
11     @Test
12     public void test3() {
13         Reporter.log("这是我们自己写的日志");
14         throw new RuntimeException("这是我们自己的运行时异常");
15     }
16 }

3.testng.xml配置

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <suite name="我们自己的接口测试套件">
 3     <test name="这些是测试模块">
 4         <classes>
 5             <class name="com.test.testng.Demo1">
 6                 <method>
 7                     <include name="test1"/>
 8                     <include name="test2"/>
 9                     <include name="test3"/>
10                 </method>
11             </class>
12         </classes>
13     </test>
14     <listeners>
15         <listener class-name="com.vimalselvam.testng.listener.ExtentTestNgFormatter"/>
16     </listeners>
17 </suite>

4.解决css无法加载

4.1新建ExtentTestNGIReporterListener实现IReporter,设置静态文件的DNS

  1 import com.aventstack.extentreports.ExtentReports;
  2 import com.aventstack.extentreports.ExtentTest;
  3 import com.aventstack.extentreports.ResourceCDN;
  4 import com.aventstack.extentreports.Status;
  5 import com.aventstack.extentreports.model.TestAttribute;
  6 import com.aventstack.extentreports.reporter.ExtenthtmlReporter;
  7 import com.aventstack.extentreports.reporter.configuration.ChartLocation;
  8 import com.aventstack.extentreports.reporter.configuration.Theme;
  9 import org.testng.*;
 10 import org.testng.xml.XmlSuite;
 11 
 12 import java.io.File;
 13 import java.util.*;
 14 
 15 public class ExtentTestNGIReporterListener implements IReporter {
 16     //生成的路径以及文件名
 17     private static final String OUTPUT_FOLDER = "test-output/";
 18     private static final String FILE_NAME = "index.html";
 19 
 20     private ExtentReports extent;
 21 
 22     @Override
 23     public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
 24         init();
 25         boolean createSuiteNode = false;
 26         if(suites.size()>1){
 27             createSuiteNode=true;
 28         }
 29         for (ISuite suite : suites) {
 30             Map<String, ISuiteResult> result = suite.getResults();
 31             //如果suite里面没有任何用例,直接跳过,不在报告里生成
 32             if(result.size()==0){
 33                 continue;
 34             }
 35             //统计suite下的成功、失败、跳过的总用例数
 36             int suiteFailSize=0;
 37             int suitePassSize=0;
 38             int suiteSkipSize=0;
 39             ExtentTest suiteTest=null;
 40             //存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。
 41             if(createSuiteNode){
 42                 suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName());
 43             }
 44             boolean createSuiteResultNode = false;
 45             if(result.size()>1){
 46                 createSuiteResultNode=true;
 47             }
 48             for (ISuiteResult r : result.values()) {
 49                 ExtentTest resultNode;
 50                 ITestContext context = r.getTestContext();
 51                 if(createSuiteResultNode){
 52                     //没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。
 53                     if( null == suiteTest){
 54                         resultNode = extent.createTest(r.getTestContext().getName());
 55                     }else{
 56                         resultNode = suiteTest.createNode(r.getTestContext().getName());
 57                     }
 58                 }else{
 59                     resultNode = suiteTest;
 60                 }
 61                 if(resultNode != null){
 62                     resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName());
 63                     if(resultNode.getModel().hasCategory()){
 64                         resultNode.assignCategory(r.getTestContext().getName());
 65                     }else{
 66                         resultNode.assignCategory(suite.getName(),r.getTestContext().getName());
 67                     }
 68                     resultNode.getModel().setStartTime(r.getTestContext().getStartDate());
 69                     resultNode.getModel().setEndTime(r.getTestContext().getEndDate());
 70                     //统计SuiteResult下的数据
 71                     int passSize = r.getTestContext().getPassedTests().size();
 72                     int failSize = r.getTestContext().getFailedTests().size();
 73                     int skipSize = r.getTestContext().getSkippedTests().size();
 74                     suitePassSize += passSize;
 75                     suiteFailSize += failSize;
 76                     suiteSkipSize += skipSize;
 77                     if(failSize>0){
 78                         resultNode.getModel().setStatus(Status.FAIL);
 79                     }
 80                     resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize));
 81                 }
 82                 buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL);
 83                 buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP);
 84                 buildTestNodes(resultNode,context.getPassedTests(), Status.PASS);
 85             }
 86             if(suiteTest!= null){
 87                 suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize));
 88                 if(suiteFailSize>0){
 89                     suiteTest.getModel().setStatus(Status.FAIL);
 90                 }
 91             }
 92 
 93         }
 94         extent.flush();
 95     }
 96 
 97     private void init() {
 98         //文件夹不存在的话进行创建
 99         File reportDir= new File(OUTPUT_FOLDER);
100         if(!reportDir.exists()&& !reportDir .isDirectory()){
101             reportDir.mkdir();
102         }
103         ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
104         // 设置静态文件的DNS
105         //怎么样解决cdn.rawgit.com访问不了的情况
106         htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
107 
108         htmlReporter.config().setDocumentTitle("api自动化测试报告");
109         htmlReporter.config().setReportName("api自动化测试报告");
110         htmlReporter.config().setChartVisibilityOnOpen(true);
111         htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
112         htmlReporter.config().setTheme(Theme.STANDARD);
113         htmlReporter.config().setCSS(".node.level-1  ul{ display:none;} .node.level-1.active ul{display:block;}");
114         extent = new ExtentReports();
115         extent.attachReporter(htmlReporter);
116         extent.setReportUsesManualConfiguration(true);
117     }
118 
119     private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) {
120         //存在父节点时,获取父节点的标签
121         String[] categories=new String[0];
122         if(extenttest != null ){
123             List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();
124             categories = new String[categoryList.size()];
125             for(int index=0;index<categoryList.size();index++){
126                 categories[index] = categoryList.get(index).getName();
127             }
128         }
129 
130         ExtentTest test;
131 
132         if (tests.size() > 0) {
133             //调整用例排序,按时间排序
134             Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() {
135                 @Override
136                 public int compare(ITestResult o1, ITestResult o2) {
137                     return o1.getStartMillis()<o2.getStartMillis()?-1:1;
138                 }
139             });
140             treeSet.addAll(tests.getAllResults());
141             for (ITestResult result : treeSet) {
142                 Object[] parameters = result.getParameters();
143                 String name="";
144                 //如果有参数,则使用参数的toString组合代替报告中的name
145                 for(Object param:parameters){
146                     name+=param.toString();
147                 }
148                 if(name.length()>0){
149                     if(name.length()>50){
150                         name= name.substring(0,49)+"...";
151                     }
152                 }else{
153                     name = result.getMethod().getMethodName();
154                 }
155                 if(extenttest==null){
156                     test = extent.createTest(name);
157                 }else{
158                     //作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。
159                     test = extenttest.createNode(name).assignCategory(categories);
160                 }
161                 for (String group : result.getMethod().getGroups())
162                     test.assignCategory(group);
163 
164                 List<String> outputList = Reporter.getOutput(result);
165                 for(String output:outputList){
166                     //将用例的log输出报告中
167                     test.debug(output);
168                 }
169                 if (result.getThrowable() != null) {
170                     test.log(status, result.getThrowable());
171                 }
172                 else {
173                     test.log(status, "Test " + status.toString().toLowerCase() + "ed");
174                 }
175 
176                 test.getModel().setStartTime(getTime(result.getStartMillis()));
177                 test.getModel().setEndTime(getTime(result.getEndMillis()));
178             }
179         }
180     }
181 
182     private Date getTime(long millis) {
183         Calendar calendar = Calendar.getInstance();
184         calendar.setTimeInMillis(millis);
185         return calendar.getTime();
186     }
187 }

5.修改testng.ml监听器设置

<listeners>
        <listener class-name="com.test.testng.ExtentTestNGIReporterListener"></listener>
    </listeners>

6.再次运行testng.xml,生成报告后,test-output/index.html,得到正常css样式的报告

技术图片

以上是关于使用ExtentReport生成漂亮的测试报告的主要内容,如果未能解决你的问题,请参考以下文章

接口自动化框架(java)--5.通过testng.xml生成extentreport测试报告

httprunner 2.x学习9-生成测试报告ExtentReport('dict object' has no attribute 'meta_data'问题已解决

.NET自动化测试的工具链:Selenium+NUnit+ExtentReport

测试报告ExtentReport改进

使用allure生成漂亮的测试报告

TestNG使用ExtentReports生成漂亮的测试报告