使用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'问题已解决