也许是最好的测试 告框架之一-ExtentReports

引言

自动化测试一个漂亮的测试 告是必不可少的。世面上主流的测试 告框架是Extent Report和Allure Report。两个都特别好,今天介绍是Extent Report。Extent Report有一些功能是收费的,比如:邮件 告。但是通常免费的功能已经满足我们需求了。

依赖

创建一个Maven项目。添加如下依赖:

<dependency>      <groupId>org.testng</groupId>      <artifactId>testng</artifactId>      <version>6.14.3</version>    </dependency>    <dependency>      <groupId>com.relevantcodes</groupId>      <artifactId>extentreports</artifactId>      <version>2.41.2</version>    </dependency>    <dependency>      <groupId>com.vimalselvam</groupId>      <artifactId>testng-extentsreport</artifactId>      <version>1.3.1</version>    </dependency>    <dependency>      <groupId>com.aventstack</groupId>      <artifactId>extentreports</artifactId>      <version>3.0.6</version>    </dependency>

新建测试用例

新建一个TestNG测试类,随便写几条测试用例。

public class DemoTest{  @Test  public  void  test1(){    Assert.assertEquals(1,2);  }  @Test  public void test2(){    Assert.assertEquals(1,1);  }  @Test  public  void test3(){    Assert.assertEquals("aaa","aaa");  }  @Test  public void logDemo(){    Reporter.log("这是我自己写的日志");    throw new RuntimeException("这是我自己运行时候的异常");  }}

Listener

Testng的高级功能listener,不了解的话可以看一下官方文档。我们这里创建一个listener用来生成测试 告。代码如下:

package com.demo.listeners;import com.aventstack.extentreports.ExtentReports;import com.aventstack.extentreports.ExtentTest;import com.aventstack.extentreports.ResourceCDN;import com.aventstack.extentreports.Status;?import com.aventstack.extentreports.model.TestAttribute;import com.aventstack.extentreports.reporter.ExtentHtmlReporter;import com.aventstack.extentreports.reporter.configuration.ChartLocation;import com.aventstack.extentreports.reporter.configuration.Theme;import org.testng.*;import org.testng.xml.XmlSuite;?import java.io.File;import java.util.*;?public class ExtentTestNGIReporterListener implements IReporter {  //生成的路径以及文件名  private static final String OUTPUT_FOLDER = "test-output/";  private static final String FILE_NAME = "index.html";?  private ExtentReports extent;?  @Override  public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {    init();    boolean createSuiteNode = false;    if(suites.size()>1){      createSuiteNode=true;    }    for (ISuite suite : suites) {      Map<String, ISuiteResult> result = suite.getResults();      //如果suite里面没有任何用例,直接跳过,不在 告里生成      if(result.size()==0){        continue;      }      //统计suite下的成功、失败、跳过的总用例数      int suiteFailSize=0;      int suitePassSize=0;      int suiteSkipSize=0;      ExtentTest suiteTest=null;      //存在多个suite的情况下,在 告中将同一个一个suite的测试结果归为一类,创建一级节点。      if(createSuiteNode){        suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName());      }      boolean createSuiteResultNode = false;      if(result.size()>1){        createSuiteResultNode=true;      }      for (ISuiteResult r : result.values()) {        ExtentTest resultNode;        ITestContext context = r.getTestContext();        if(createSuiteResultNode){          //没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。          if( null == suiteTest){            resultNode = extent.createTest(r.getTestContext().getName());          }else{            resultNode = suiteTest.createNode(r.getTestContext().getName());          }        }else{          resultNode = suiteTest;        }        if(resultNode != null){          resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName());          if(resultNode.getModel().hasCategory()){            resultNode.assignCategory(r.getTestContext().getName());          }else{            resultNode.assignCategory(suite.getName(),r.getTestContext().getName());          }          resultNode.getModel().setStartTime(r.getTestContext().getStartDate());          resultNode.getModel().setEndTime(r.getTestContext().getEndDate());          //统计SuiteResult下的数据          int passSize = r.getTestContext().getPassedTests().size();          int failSize = r.getTestContext().getFailedTests().size();          int skipSize = r.getTestContext().getSkippedTests().size();          suitePassSize += passSize;          suiteFailSize += failSize;          suiteSkipSize += skipSize;          if(failSize>0){            resultNode.getModel().setStatus(Status.FAIL);          }          resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize));        }        buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL);        buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP);        buildTestNodes(resultNode,context.getPassedTests(), Status.PASS);      }      if(suiteTest!= null){        suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize));        if(suiteFailSize>0){          suiteTest.getModel().setStatus(Status.FAIL);        }      }?    }//        for (String s : Reporter.getOutput()) {//            extent.setTestRunnerOutput(s);//        }?    extent.flush();  }?  private void init() {    //文件夹不存在的话进行创建    File reportDir= new File(OUTPUT_FOLDER);    if(!reportDir.exists()&& !reportDir .isDirectory()){      reportDir.mkdir();    }    ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);    // 设置静态文件的DNS    //怎么样解决cdn.rawgit.com访问不了的情况    htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);?    htmlReporter.config().setDocumentTitle("api自动化测试 告");    htmlReporter.config().setReportName("api自动化测试 告");    htmlReporter.config().setChartVisibilityOnOpen(true);    htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);    htmlReporter.config().setTheme(Theme.STANDARD);    //htmlReporter.config().setEncoding("gb2312");    htmlReporter.config().setCSS(".node.level-1  ul{ display:none;} .node.level-1.active ul{display:block;}");    extent = new ExtentReports();    extent.attachReporter(htmlReporter);    extent.setReportUsesManualConfiguration(true);  }?  private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) {    //存在父节点时,获取父节点的标签    String[] categories=new String[0];    if(extenttest != null ){      List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();      categories = new String[categoryList.size()];      for(int index=0;index<categoryList.size();index++){        categories[index] = categoryList.get(index).getName();      }    }?    ExtentTest test;?    if (tests.size() > 0) {      //调整用例排序,按时间排序      Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() {        @Override        public int compare(ITestResult o1, ITestResult o2) {          return o1.getStartMillis()<o2.getStartMillis()?-1:1;        }      });      treeSet.addAll(tests.getAllResults());      for (ITestResult result : treeSet) {        Object[] parameters = result.getParameters();        String name="";        //如果有参数,则使用参数的toString组合代替 告中的name        for(Object param:parameters){          name+=param.toString();        }        if(name.length()>0){          if(name.length()>50){            name= name.substring(0,49)+"...";          }        }else{          name = result.getMethod().getMethodName();        }        if(extenttest==null){          test = extent.createTest(name);        }else{          //作为子节点进行创建时,设置同父节点的标签一致,便于 告检索。          test = extenttest.createNode(name).assignCategory(categories);        }        //test.getModel().setDescription(description.toString());        //test = extent.createTest(result.getMethod().getMethodName());        for (String group : result.getMethod().getGroups())          test.assignCategory(group);?        List<String> outputList = Reporter.getOutput(result);        for(String output:outputList){          //将用例的log输出 告中          test.debug(output);        }        if (result.getThrowable() != null) {          test.log(status, result.getThrowable());        }        else {          test.log(status, "Test " + status.toString().toLowerCase() + "ed");        }?        test.getModel().setStartTime(getTime(result.getStartMillis()));        test.getModel().setEndTime(getTime(result.getEndMillis()));      }    }  }?  private Date getTime(long millis) {    Calendar calendar = Calendar.getInstance();    calendar.setTimeInMillis(millis);    return calendar.getTime();  }}?

Suite文件

在Resources文件夹创建一个TestNG的Suite文件叫testng.xml。内容如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"><suite name="Suite">  <listeners>    <listener class-name="com.demo.listeners.ExtentTestNGIReporterListener"></listener>  </listeners>  <test name="Test">    <classes>      <class name="com.demo.tests.DemoTest" />    </classes>  </test></suite> ?

此时我们的项目目录结构如下:

执行右键testng.xml,执行测试用例。在test-output下会生成一个index.html测试 告。

告打开如下:

结语

Extent Report还提供了自己的 告服务器ExtentX,可以把每次执行后 告都存在服务器上。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年7月12日
下一篇 2020年7月12日

相关推荐