testng+Extentreport監聽器出測試報告
阿新 • • 發佈:2018-11-12
監聽器:
1 package listener; 2 3 import com.aventstack.extentreports.ExtentReports; 4 import com.aventstack.extentreports.ExtentTest; 5 import com.aventstack.extentreports.ResourceCDN; 6 import com.aventstack.extentreports.Status; 7 import com.aventstack.extentreports.model.TestAttribute;8 import com.aventstack.extentreports.reporter.ExtentHtmlReporter; 9 import com.aventstack.extentreports.reporter.configuration.ChartLocation; 10 import com.aventstack.extentreports.reporter.configuration.Theme; 11 import org.testng.*; 12 import org.testng.xml.XmlSuite; 13 14 import java.io.File;15 import java.util.*; 16 17 public class ExtentTestNGIReportListener implements IReporter { 18 19 //生成的路徑以及檔名 20 private static final String OUTPUT_FOLDER = "test-output/"; 21 private static final String FILE_NAME = "meiju_apitest.html"; 22 23 private ExtentReports extent; 2425 @Override 26 public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) { 27 init(); 28 boolean createSuiteNode = false; 29 if(suites.size()>1){ 30 createSuiteNode=true; 31 } 32 for (ISuite suite : suites) { 33 Map<String, ISuiteResult> result = suite.getResults(); 34 //如果suite裡面沒有任何用例,直接跳過,不在報告裡生成 35 if(result.size()==0){ 36 continue; 37 } 38 //統計suite下的成功、失敗、跳過的總用例數 39 int suiteFailSize=0; 40 int suitePassSize=0; 41 int suiteSkipSize=0; 42 ExtentTest suiteTest=null; 43 //存在多個suite的情況下,在報告中將同一個一個suite的測試結果歸為一類,建立一級節點。 44 if(createSuiteNode){ 45 suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName()); 46 } 47 boolean createSuiteResultNode = false; 48 if(result.size()>1){ 49 createSuiteResultNode=true; 50 } 51 for (ISuiteResult r : result.values()) { 52 ExtentTest resultNode; 53 ITestContext context = r.getTestContext(); 54 if(createSuiteResultNode){ 55 //沒有建立suite的情況下,將在SuiteResult的建立為一級節點,否則建立為suite的一個子節點。 56 if( null == suiteTest){ 57 resultNode = extent.createTest(r.getTestContext().getName()); 58 }else{ 59 resultNode = suiteTest.createNode(r.getTestContext().getName()); 60 } 61 }else{ 62 resultNode = suiteTest; 63 } 64 if(resultNode != null){ 65 resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName()); 66 if(resultNode.getModel().hasCategory()){ 67 resultNode.assignCategory(r.getTestContext().getName()); 68 }else{ 69 resultNode.assignCategory(suite.getName(),r.getTestContext().getName()); 70 } 71 resultNode.getModel().setStartTime(r.getTestContext().getStartDate()); 72 resultNode.getModel().setEndTime(r.getTestContext().getEndDate()); 73 //統計SuiteResult下的資料 74 int passSize = r.getTestContext().getPassedTests().size(); 75 int failSize = r.getTestContext().getFailedTests().size(); 76 int skipSize = r.getTestContext().getSkippedTests().size(); 77 suitePassSize += passSize; 78 suiteFailSize += failSize; 79 suiteSkipSize += skipSize; 80 if(failSize>0){ 81 resultNode.getModel().setStatus(Status.FAIL); 82 } 83 resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize)); 84 } 85 buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL); 86 buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP); 87 buildTestNodes(resultNode,context.getPassedTests(), Status.PASS); 88 } 89 if(suiteTest!= null){ 90 suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize)); 91 if(suiteFailSize>0){ 92 suiteTest.getModel().setStatus(Status.FAIL); 93 } 94 } 95 96 } 97 // for (String s : Reporter.getOutput()) { 98 // extent.setTestRunnerOutput(s); 99 // } 100 101 extent.flush(); 102 } 103 104 private void init() { 105 //資料夾不存在的話進行建立 106 File reportDir= new File(OUTPUT_FOLDER); 107 if(!reportDir.exists()&& !reportDir .isDirectory()){ 108 reportDir.mkdir(); 109 } 110 ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME); 111 // 設定靜態檔案的DNS 112 //怎麼樣解決cdn.rawgit.com訪問不了的情況 113 htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS); 114 115 htmlReporter.config().setDocumentTitle("api自動化測試報告"); 116 htmlReporter.config().setReportName("api自動化測試報告"); 117 htmlReporter.config().setChartVisibilityOnOpen(true); 118 htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP); 119 htmlReporter.config().setTheme(Theme.STANDARD); 120 htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}"); 121 extent = new ExtentReports(); 122 extent.attachReporter(htmlReporter); 123 extent.setReportUsesManualConfiguration(true); 124 } 125 126 private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) { 127 //存在父節點時,獲取父節點的標籤 128 String[] categories=new String[0]; 129 if(extenttest != null ){ 130 List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll(); 131 categories = new String[categoryList.size()]; 132 for(int index=0;index<categoryList.size();index++){ 133 categories[index] = categoryList.get(index).getName(); 134 } 135 } 136 137 ExtentTest test; 138 139 if (tests.size() > 0) { 140 //調整用例排序,按時間排序 141 Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() { 142 @Override 143 public int compare(ITestResult o1, ITestResult o2) { 144 return o1.getStartMillis()<o2.getStartMillis()?-1:1; 145 } 146 }); 147 treeSet.addAll(tests.getAllResults()); 148 for (ITestResult result : treeSet) { 149 Object[] parameters = result.getParameters(); 150 String name=""; 151 //如果有引數,則使用引數的toString組合代替報告中的name 152 for(Object param:parameters){ 153 name+=param.toString(); 154 } 155 if(name.length()>0){ 156 if(name.length()>50){ 157 name= name.substring(0,49)+"..."; 158 } 159 }else{ 160 name = result.getMethod().getMethodName(); 161 } 162 if(extenttest==null){ 163 test = extent.createTest(name); 164 }else{ 165 //作為子節點進行建立時,設定同父節點的標籤一致,便於報告檢索。 166 test = extenttest.createNode(name).assignCategory(categories); 167 } 168 //test.getModel().setDescription(description.toString()); 169 //test = extent.createTest(result.getMethod().getMethodName()); 170 for (String group : result.getMethod().getGroups()) 171 test.assignCategory(group); 172 173 List<String> outputList = Reporter.getOutput(result); 174 for(String output:outputList){ 175 //將用例的log輸出報告中 176 test.debug(output); 177 } 178 if (result.getThrowable() != null) { 179 test.log(status, result.getThrowable()); 180 } 181 else { 182 test.log(status, "Test " + status.toString().toLowerCase() + "ed"); 183 } 184 185 test.getModel().setStartTime(getTime(result.getStartMillis())); 186 test.getModel().setEndTime(getTime(result.getEndMillis())); 187 } 188 } 189 } 190 191 private Date getTime(long millis) { 192 Calendar calendar = Calendar.getInstance(); 193 calendar.setTimeInMillis(millis); 194 return calendar.getTime(); 195 } 196 }
testng.xml:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > 3 4 <suite name="測試套件1"> 5 6 <test name="login"> 7 8 <classes> 9 <class name="xxx.suite.SuiteConfig"/> 10 <class name="xxx.login.ToLogin"/> 11 <class name="xxx.login.LoginIn"/> 12 <class name="xxx.login.GetCurrentUser"/> 13 <class name="xxx.login.LoginOut"></class> 14 <class name="xxx.objectLibrary.GetLibraryDetailById"></class> 15 16 </classes> 17 </test> 18 <listeners> 19 <!--<listener class-name="com.vimalselvam.testng.listener.ExtentTestNgFormatter"/>--> 20 <listener class-name="listener.ExtentTestNGIReportListener"/> 21 </listeners> 22 </suite>
pom.xml:jar包
1 <!-- extentreports --> 2 <dependency> 3 <groupId>com.relevantcodes</groupId> 4 <artifactId>extentreports</artifactId> 5 <version>2.41.1</version> 6 </dependency> 7 <dependency> 8 <groupId>com.vimalselvam</groupId> 9 <artifactId>testng-extentsreport</artifactId> 10 <version>1.3.1</version> 11 </dependency> 12 <dependency> 13 <groupId>com.aventstack</groupId> 14 <artifactId>extentreports</artifactId> 15 <version>3.0.6</version> 16 </dependency> 17 <!-- extentreports -->
生成的測試報告的樣式:
可以監聽到testng中執行的案例,數量,通過,失敗,失敗日誌,按分組篩選展示等資訊;
需修改下,第113行程式碼:
//怎麼樣解決cdn.rawgit.com訪問不了的情況
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);