自己做直播网站,给一个网站风格做定义,广安网站设计,销帮帮crmTestNG与ExtentReport集成
目录
1 通过实现ITestListener的方法添加Reporter log 1.1 MyTestListener设置 1.2 输出结果 2 TestNG与ExtentReporter集成 2.1 项目结构 2.2 MyExtentReportListener设置 2.3 单多Suite、Test组合测试 2.3.1 单Suite单Test 2.3…TestNG与ExtentReport集成
目录
1 通过实现ITestListener的方法添加Reporter log 1.1 MyTestListener设置 1.2 输出结果 2 TestNG与ExtentReporter集成 2.1 项目结构 2.2 MyExtentReportListener设置 2.3 单多Suite、Test组合测试 2.3.1 单Suite单Test 2.3.2 单Suite多Test 2.3.3 多Suite
源代码interface-test-framework.zip
1 通过实现ITestListener的方法添加Reporter log
TestNG的Listener列表
TestNG提供了一组预定义的Listener Java接口这些接口全部继承自TestNG的 ITestNGListener接口。用户创建这些接口的实现类并把它们加入到 TestNG 中TestNG便会在测试运行的不同时刻调用这些类中的接口方法:
IExecutionListener 监听TestNG运行的启动和停止。IAnnotationTransformer 注解转换器用于TestNG测试类中的注解。ISuiteListener 测试套件监听器监听测试套件的启动和停止。ITestListener 测试方法执行监听。IConfigurationListener 监听配置方法相关的接口。IMethodInterceptor 拦截器调整测试方法的执行顺序。IInvokedMethodListener 测试方法拦截监听用于获取被TestNG调用的在Method的Before 和After方法监听器。该方法只会被配置和测试方法调用。IHookable 若测试类实现了该接口当Test方法被发现时它的run()方法将会被调用来替代Test方法。这个测试方法通常在IHookCallBack的callback之上调用比较适用于需要JASS授权的测试类。IReporter 实现该接口可以生成一份测试报告。
本文将着重介绍最常用到的两个Listener ITestListener与Ireporter接口。
1.1 MyTestListener设置
通过实现ITestListener的方法添加Reporter.log
MyTestListener.java
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.Reporter;public class MyTestListener implements ITestListener {//用例执行结束后用例执行成功时调用public void onTestSuccess(ITestResult tr) {logTestEnd(tr, Success);}//用例执行结束后用例执行失败时调用public void onTestFailure(ITestResult tr) {logTestEnd(tr, Failed);}//用例执行结束后用例执行skip时调用public void onTestSkipped(ITestResult tr) {logTestEnd(tr, Skipped);}//每次方法失败但是已经使用successPercentage进行注释时调用并且此失败仍保留在请求的成功百分比之内。public void onTestFailedButWithinSuccessPercentage(ITestResult tr) {logTestEnd(tr, FailedButWithinSuccessPercentage);}//每次调用测试Test之前调用public void onTestStart(ITestResult result) {logTestStart(result);}//在测试类被实例化之后调用并在调用任何配置方法之前调用。public void onStart(ITestContext context) {return;}//在所有测试运行之后调用并且所有的配置方法都被调用public void onFinish(ITestContext context) {return;}// 在用例执行结束时打印用例的执行结果信息protected void logTestEnd(ITestResult tr, String result) {Reporter.log(String.format(-------------Result: %s-------------, result), true);}// 在用例开始时打印用例的一些信息比如Test对应的方法名用例的描述等等protected void logTestStart(ITestResult tr) {Reporter.log(String.format(-------------Run: %s.%s---------------, tr.getTestClass().getName(), tr.getMethod().getMethodName()), true);Reporter.log(String.format(用例描述: %s, 优先级: %s, tr.getMethod().getDescription(), tr.getMethod().getPriority()),true);return;}
}1.2 输出结果
SmkDemo1.java
import com.demo.listener.MyTestListener;
import org.testng.Assert;
import org.testng.Reporter;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;Listeners({MyTestListener.class})
public class SmkDemo1 {Test(description测testPass11的描述,priority 1,groups {分组1})public void testPass11(){Reporter.log(Test11的第一步,true);Assert.assertEquals(1,1);}
}输出界面显示如下 图1 log to 输出界面
2 TestNG与ExtentReporter集成
2.1 项目结构 图2 项目结构
pom.xml
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.demo/groupIdartifactIdinterface-test-framework/artifactIdversion1.0-SNAPSHOT/versiondependencies!-- 测试报告插件和testng的结合 --dependencygroupIdcom.vimalselvam/groupIdartifactIdtestng-extentsreport/artifactIdversion1.3.1/version/dependency!-- extentreports测试报告插件 --dependencygroupIdcom.aventstack/groupIdartifactIdextentreports/artifactIdversion3.0.6/version/dependencydependencygroupIdorg.testng/groupIdartifactIdtestng/artifactIdversion7.1.0/version/dependency/dependencies
/project2.2 MyExtentReportListener设置
MyExtentReporterListener.java
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.ResourceCDN;
import com.aventstack.extentreports.Status;
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 MyExtentReporterListener implements IReporter {//生成的路径以及文件名private static final String OUTPUT_FOLDER test-output/;private static final String FILE_NAME report.html;private ExtentReports extent;public void generateReport(ListXmlSuite xmlSuites, ListISuite suites, String outputDirectory) {init();boolean createSuiteNode false;if(suites.size()1){createSuiteNodetrue;}for (ISuite suite : suites) {MapString, ISuiteResult result suite.getResults();//如果suite里面没有任何用例直接跳过不在报告里生成if(result.size()0){continue;}//统计suite下的成功、失败、跳过的总用例数int suiteFailSize0;int suitePassSize0;int suiteSkipSize0;ExtentTest suiteTestnull;//存在多个suite的情况下在报告中将同一个一个suite的测试结果归为一类创建一级节点。if(createSuiteNode){
// suiteTest extent.createTest(suite.getName()).assignCategory(suite.getName());suiteTest extent.createTest(suite.getName());}boolean createSuiteResultNode false;if(result.size()1){createSuiteResultNodetrue;}for (ISuiteResult r : result.values()) {ExtentTest resultNodenull;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;}String[] categoriesnew String[1];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());categories[0]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(failSize0){resultNode.getModel().setStatus(Status.FAIL);}resultNode.getModel().setDescription(String.format(Pass: %s ; Fail: %s ; Skip: %s ;,passSize,failSize,skipSize));}buildTestNodes(resultNode,categories,context.getFailedTests(), Status.FAIL);buildTestNodes(resultNode,categories,context.getSkippedTests(), Status.SKIP);buildTestNodes(resultNode,categories,context.getPassedTests(), Status.PASS);}if(suiteTest! null){suiteTest.getModel().setDescription(String.format(Pass: %s ; Fail: %s ; Skip: %s ;,suitePassSize,suiteFailSize,suiteSkipSize));if(suiteFailSize0){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访问不了的问题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().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, String[] categories, IResultMap tests, Status status) {
// //存在父节点时获取父节点的标签
// String[] categoriesnew String[0];
// if(extenttest ! null ){
// ListTestAttribute categoryList extenttest.getModel().getCategoryContext().getAll();
// categories new String[categoryList.size()];
// for(int index0;indexcategoryList.size();index){
// categories[index] categoryList.get(index).getName();
// }
// }ExtentTest test;if (tests.size() 0) {//调整用例排序按时间排序SetITestResult treeSet new TreeSetITestResult(new ComparatorITestResult() {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组合代替报告中的namefor(Object param:parameters){nameparam.toString();}if(name.length()0){if(name.length()50){name name.substring(0,49)...;}}else{name result.getMethod().getMethodName();}if(extenttestnull){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);ListString 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();}
}2.3 单多Suite、Test组合测试
2.3.1 单Suite单Test
testngSingleSuiteSingleTest.xml
?xml version1.0 encodingUTF-8?!DOCTYPE suite SYSTEM http://testng.org/testng-1.0.dtd
suite nameSingleSuitetest nameSingleTest verbose1 preserve-ordertrue classesclass namecom.demo.testcase.smoke.SmkDemo1/classclass namecom.demo.testcase.sit.SitDemo2/class/classes/test!--配置监听器--listenerslistener class-namecom.demo.listener.MyTestListener/listener class-namecom.demo.listener.MyExtentReporterListener//listeners
/suite图3 单Suite单Test总览 图4 单Suite单Test分组 图5 单Suite单Test错误分组 图6 单Suite单Test Dashboard
2.3.2 单Suite多Test
testngSingleSuiteDoubleTest.xml
?xml version1.0 encodingUTF-8?!DOCTYPE suite SYSTEM http://testng.org/testng-1.0.dtd
suite nameSingleSuitetest nameDoubleTest1 verbose1 preserve-ordertrue classesclass namecom.demo.testcase.smoke.SmkDemo1/class/classes/testtest nameDoubleTest2 verbose1 preserve-ordertrue classesclass namecom.demo.testcase.sit.SitDemo2/class/classes/test!--配置监听器--listenerslistener class-namecom.demo.listener.MyTestListener/listener class-namecom.demo.listener.MyExtentReporterListener//listeners
/suite图7 单Suite多Test总览 图8 单Suite多Test分组
2.3.3 多Suite
testngDoubleSuite.xml
?xml version1.0 encodingUTF-8?!DOCTYPE suite SYSTEM http://testng.org/testng-1.0.dtd
suite nameDoubleSuitesuite-filessuite-file pathtestngSingleSuiteSingleTest.xml/suite-file pathtestngSingleSuiteDoubleTest.xml//suite-files!--配置监听器--listenerslistener class-namecom.demo.listener.MyTestListener/listener class-namecom.demo.listener.MyExtentReporterListener//listeners
/suite图9 多Suite总览1 图10 多Suite总览2 图11 多Suite分组
参考
[1] testng框架Listener介绍及测试结果的收集
[2] TestNG执行的日志ITestListener与结果IReporter
[3] TestNG执行的日志ITestListener与结果IReporter
[4] TestNg Beginner’s Guide–阅后总结之Textng.xml
[5] TestNg Beginner’s Guide–阅后总结之TestNg注解
ExtentReports 另一种方法
引言
在走进Java接口测试之测试框架TestNG 中我们详细介绍了 TestNG 的各种用法 在本文中我将详细介绍如何将 ExtentReports 测试报告与TestNG集成。
ExtentReports 简介
主要特点
生成的报告简洁美观生成的单html方便 Jenkins 集成发邮件自带集中展示历史报告的服务端支持 Java 和 .Net
TestNG 原生报告有点丑信息整理有点乱。ExtentReports 是用于替换TestNG 原生报告。当然也可以使用 ReportNg个人偏好 ExtentReports 样式。
官网已经给了很多demo了大家可以参考练习。
官网http://extentreports.com/
客户端
https://github.com/anshooarora/extentreports-java/commits/master
服务端:https://github.com/anshooarora/extentx
Step-1添加 Maven 依赖包
引入pom.xml
!--引入extentreports相关包--dependencygroupIdcom.aventstack/groupIdartifactIdextentreports/artifactIdversion3.1.5/versionscopeprovided/scope/dependencydependencygroupIdcom.vimalselvam/groupIdartifactIdtestng-extentsreport/artifactIdversion1.3.1/version/dependencydependencygroupIdcom.relevantcodes/groupIdartifactIdextentreports/artifactIdversion2.41.2/version/dependency!--引入testng测试框架--dependencygroupIdorg.testng/groupIdartifactIdtestng/artifactIdversion6.14.3/versionscopecompile/scope/dependencyStep-2重写 ExtentTestNgFormatter 类
主要基于以下两项原因
支持报告中展示更多状态类型的测试结果例如成功、失败、警告、跳过等。因为不支持cdn.rawgit.com访问故替css访问方式。
创建 MyExtentTestNgFormatter 类
下载 ExtentReportes 源码找到 ExtentTestNgFormatter 类Listener 目录下创建 MyExtentTestNgFormatter.java 类直接继承 ExtentTestNgFormatter 类。
public class MyExtentTestNgFormatter extends ExtentTestNgFormatter {解决CDN无法访问
构造方法加入
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);具体代码如下
public MyExtentTestNgFormatter() {setInstance(this);testRunnerOutput new ArrayList();String reportPathStr System.getProperty(reportPath);File reportPath;try {reportPath new File(reportPathStr);} catch (NullPointerException e) {reportPath new File(TestNG.DEFAULT_OUTPUTDIR);}if (!reportPath.exists()) {if (!reportPath.mkdirs()) {throw new RuntimeException(Failed to create output run directory);}}File reportFile new File(reportPath, report.html);File emailReportFile new File(reportPath, emailable-report.html);htmlReporter new ExtentHtmlReporter(reportFile);EmailReporter emailReporter new EmailReporter(emailReportFile);reporter new ExtentReports();// 如果cdn.rawgit.com访问不了可以设置为ResourceCDN.EXTENTREPORTS或者ResourceCDN.GITHUBhtmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);reporter.attachReporter(htmlReporter, emailReporter);}重写 onstart 方法
新建一个类名为MyReporter一个静态ExtentTest的引用。
Listener 包下 MyReporter.java
public class MyReporter { public static ExtentTest report; }MyExtentTestNgFormatter.java
public void onStart(ITestContext iTestContext) {ISuite iSuite iTestContext.getSuite();ExtentTest suite (ExtentTest) iSuite.getAttribute(SUITE_ATTR);ExtentTest testContext suite.createNode(iTestContext.getName());// 将MyReporter.report静态引用赋值为testContext。// testContext是Test每个测试用例时需要的。report.log可以跟随具体的测试用例。另请查阅源码。MyReporter.report testContext;iTestContext.setAttribute(testContext, testContext);}自定义配置
测试报告默认是在工程根目录下创建 test-output/ 文件夹下名为 report.html、 emailable-report.html。可根据各自需求在构造方法中修改。
public MyExtentTestNgFormatter() {setInstance(this);testRunnerOutput new ArrayList();// reportPath报告路径String reportPathStr System.getProperty(reportPath);File reportPath;try {reportPath new File(reportPathStr);} catch (NullPointerException e) {reportPath new File(TestNG.DEFAULT_OUTPUTDIR);}if (!reportPath.exists()) {if (!reportPath.mkdirs()) {throw new RuntimeException(Failed to create output run directory);}}// 报告名report.htmlFile reportFile new File(reportPath, report.html);// 邮件报告名emailable-report.htmlFile emailReportFile new File(reportPath, emailable-report.html);htmlReporter new ExtentHtmlReporter(reportFile);EmailReporter emailReporter new EmailReporter(emailReportFile);reporter new ExtentReports();reporter.attachReporter(htmlReporter, emailReporter);}report.log
report.log 支持多种玩法
// 根据状态不同添加报告。型如警告 MyReporter.report.log(Status.WARNING, 接口耗时(ms) String.valueOf(time));直接从TestClass 中运行时会报 MyReporter.report 的空指针错误需做判空处理。
完整代码
package com.ruoyi.listener;import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.ResourceCDN;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.vimalselvam.testng.EmailReporter;
import com.vimalselvam.testng.NodeName;
import com.vimalselvam.testng.SystemInfo;
import com.vimalselvam.testng.listener.ExtentTestNgFormatter;
import org.testng.*;
import org.testng.xml.XmlSuite;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class MyExtentTestNgFormatter extends ExtentTestNgFormatter {private static final String REPORTER_ATTR extentTestNgReporter;private static final String SUITE_ATTR extentTestNgSuite;private ExtentReports reporter;private ListString testRunnerOutput;private MapString, String systemInfo;private ExtentHtmlReporter htmlReporter;private static ExtentTestNgFormatter instance;public MyExtentTestNgFormatter() {setInstance(this);testRunnerOutput new ArrayList();// reportPath 报告路径String reportPathStr System.getProperty(reportPath);File reportPath;try {reportPath new File(reportPathStr);} catch (NullPointerException e) {reportPath new File(TestNG.DEFAULT_OUTPUTDIR);}if (!reportPath.exists()) {if (!reportPath.mkdirs()) {throw new RuntimeException(Failed to create output run directory);}}// 报告名report.htmlFile reportFile new File(reportPath, report.html);// 邮件报告名emailable-report.htmlFile emailReportFile new File(reportPath, emailable-report.html);htmlReporter new ExtentHtmlReporter(reportFile);EmailReporter emailReporter new EmailReporter(emailReportFile);reporter new ExtentReports();// 如果cdn.rawgit.com访问不了可以设置为ResourceCDN.EXTENTREPORTS或者ResourceCDN.GITHUBhtmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);reporter.attachReporter(htmlReporter, emailReporter);}/*** Gets the instance of the {link ExtentTestNgFormatter}** return The instance of the {link ExtentTestNgFormatter}*/public static ExtentTestNgFormatter getInstance() {return instance;}private static void setInstance(ExtentTestNgFormatter formatter) {instance formatter;}/*** Gets the system information map** return The system information map*/public MapString, String getSystemInfo() {return systemInfo;}/*** Sets the system information** param systemInfo The system information map*/public void setSystemInfo(MapString, String systemInfo) {this.systemInfo systemInfo;}public void onStart(ISuite iSuite) {if (iSuite.getXmlSuite().getTests().size() 0) {ExtentTest suite reporter.createTest(iSuite.getName());String configFile iSuite.getParameter(report.config);if (!Strings.isNullOrEmpty(configFile)) {htmlReporter.loadXMLConfig(configFile);}String systemInfoCustomImplName iSuite.getParameter(system.info);if (!Strings.isNullOrEmpty(systemInfoCustomImplName)) {generateSystemInfo(systemInfoCustomImplName);}iSuite.setAttribute(REPORTER_ATTR, reporter);iSuite.setAttribute(SUITE_ATTR, suite);}}private void generateSystemInfo(String systemInfoCustomImplName) {try {Class? systemInfoCustomImplClazz Class.forName(systemInfoCustomImplName);if (!SystemInfo.class.isAssignableFrom(systemInfoCustomImplClazz)) {throw new IllegalArgumentException(The given system.info class name systemInfoCustomImplName should implement the interface SystemInfo.class.getName() );}SystemInfo t (SystemInfo) systemInfoCustomImplClazz.newInstance();setSystemInfo(t.getSystemInfo());} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {throw new IllegalStateException(e);}}public void onFinish(ISuite iSuite) {}public void onTestStart(ITestResult iTestResult) {MyReporter.setTestName(iTestResult.getName());}public void onTestSuccess(ITestResult iTestResult) {}public void onTestFailure(ITestResult iTestResult) {}public void onTestSkipped(ITestResult iTestResult) {}public void onTestFailedButWithinSuccessPercentage(ITestResult iTestResult) {}public void onStart(ITestContext iTestContext) {ISuite iSuite iTestContext.getSuite();ExtentTest suite (ExtentTest) iSuite.getAttribute(SUITE_ATTR);ExtentTest testContext suite.createNode(iTestContext.getName());// 自定义报告// 将MyReporter.report 静态引用赋值为 testContext。// testContext 是 Test每个测试用例时需要的。report.log可以跟随具体的测试用例。另请查阅源码。MyReporter.report testContext;iTestContext.setAttribute(testContext, testContext);}public void onFinish(ITestContext iTestContext) {ExtentTest testContext (ExtentTest) iTestContext.getAttribute(testContext);if (iTestContext.getFailedTests().size() 0) {testContext.fail(Failed);} else if (iTestContext.getSkippedTests().size() 0) {testContext.skip(Skipped);} else {testContext.pass(Passed);}}public void beforeInvocation(IInvokedMethod iInvokedMethod, ITestResult iTestResult) {if (iInvokedMethod.isTestMethod()) {ITestContext iTestContext iTestResult.getTestContext();ExtentTest testContext (ExtentTest) iTestContext.getAttribute(testContext);ExtentTest test testContext.createNode(iTestResult.getName(), iInvokedMethod.getTestMethod().getDescription());iTestResult.setAttribute(test, test);}}public void afterInvocation(IInvokedMethod iInvokedMethod, ITestResult iTestResult) {if (iInvokedMethod.isTestMethod()) {ExtentTest test (ExtentTest) iTestResult.getAttribute(test);ListString logs Reporter.getOutput(iTestResult);for (String log : logs) {test.info(log);}int status iTestResult.getStatus();if (ITestResult.SUCCESS status) {test.pass(Passed);} else if (ITestResult.FAILURE status) {test.fail(iTestResult.getThrowable());} else {test.skip(Skipped);}for (String group : iInvokedMethod.getTestMethod().getGroups()) {test.assignCategory(group);}}}/*** Adds a screen shot image file to the report. This method should be used only in the configuration method* and the {link ITestResult} is the mandatory parameter** param iTestResult The {link ITestResult} object* param filePath The image file path* throws IOException {link IOException}*/public void addScreenCaptureFromPath(ITestResult iTestResult, String filePath) throws IOException {ExtentTest test (ExtentTest) iTestResult.getAttribute(test);test.addScreenCaptureFromPath(filePath);}/*** Adds a screen shot image file to the report. This method should be used only in the* {link org.testng.annotations.Test} annotated method** param filePath The image file path* throws IOException {link IOException}*/public void addScreenCaptureFromPath(String filePath) throws IOException {ITestResult iTestResult Reporter.getCurrentTestResult();Preconditions.checkState(iTestResult ! null);ExtentTest test (ExtentTest) iTestResult.getAttribute(test);test.addScreenCaptureFromPath(filePath);}/*** Sets the test runner output** param message The message to be logged*/public void setTestRunnerOutput(String message) {testRunnerOutput.add(message);}public void generateReport(ListXmlSuite list, ListISuite list1, String s) {if (getSystemInfo() ! null) {for (Map.EntryString, String entry : getSystemInfo().entrySet()) {reporter.setSystemInfo(entry.getKey(), entry.getValue());}}reporter.setTestRunnerOutput(testRunnerOutput);reporter.flush();}/*** Adds the new node to the test. The node name should have been set already using {link NodeName}*/public void addNewNodeToTest() {addNewNodeToTest(NodeName.getNodeName());}/*** Adds the new node to the test with the given node name.** param nodeName The name of the node to be created*/public void addNewNodeToTest(String nodeName) {addNewNode(test, nodeName);}/*** Adds a new node to the suite. The node name should have been set already using {link NodeName}*/public void addNewNodeToSuite() {addNewNodeToSuite(NodeName.getNodeName());}/*** Adds a new node to the suite with the given node name** param nodeName The name of the node to be created*/public void addNewNodeToSuite(String nodeName) {addNewNode(SUITE_ATTR, nodeName);}private void addNewNode(String parent, String nodeName) {ITestResult result Reporter.getCurrentTestResult();Preconditions.checkState(result ! null);ExtentTest parentNode (ExtentTest) result.getAttribute(parent);ExtentTest childNode parentNode.createNode(nodeName);result.setAttribute(nodeName, childNode);}/*** Adds a info log message to the node. The node name should have been set already using {link NodeName}** param logMessage The log message string*/public void addInfoLogToNode(String logMessage) {addInfoLogToNode(logMessage, NodeName.getNodeName());}/*** Adds a info log message to the node** param logMessage The log message string* param nodeName The name of the node*/public void addInfoLogToNode(String logMessage, String nodeName) {ITestResult result Reporter.getCurrentTestResult();Preconditions.checkState(result ! null);ExtentTest test (ExtentTest) result.getAttribute(nodeName);test.info(logMessage);}/*** Marks the node as failed. The node name should have been set already using {link NodeName}** param t The {link Throwable} object*/public void failTheNode(Throwable t) {failTheNode(NodeName.getNodeName(), t);}/*** Marks the given node as failed** param nodeName The name of the node* param t The {link Throwable} object*/public void failTheNode(String nodeName, Throwable t) {ITestResult result Reporter.getCurrentTestResult();Preconditions.checkState(result ! null);ExtentTest test (ExtentTest) result.getAttribute(nodeName);test.fail(t);}/*** Marks the node as failed. The node name should have been set already using {link NodeName}** param logMessage The message to be logged*/public void failTheNode(String logMessage) {failTheNode(NodeName.getNodeName(), logMessage);}/*** Marks the given node as failed** param nodeName The name of the node* param logMessage The message to be logged*/public void failTheNode(String nodeName, String logMessage) {ITestResult result Reporter.getCurrentTestResult();Preconditions.checkState(result ! null);ExtentTest test (ExtentTest) result.getAttribute(nodeName);test.fail(logMessage);}
}class MyReporter {public static ExtentTest report;private static String testName;public static String getTestName() {return testName;}public static void setTestName(String testName) {MyReporter.testName testName;}
}Step-3配置监听
在测试集合 testng.xml 文件中导入 Listener 监听类。
listeners listener class-namecom.zuozewei.extentreportdemo.listener.MyExtentTestNgFormatter/ /listenersStep-4配置报告
extent reporters支持报告的配置。目前支持的配置内容有title、主题等。 先在 src/resources/目录下添加 config/report/extent-config.xml。
?xml version1.0 encodingUTF-8?
extentreportsconfigurationtimeStampFormatyyyy-MM-dd HH:mm:ss/timeStampFormat!-- report theme --!-- standard, dark 个人喜好暗色 --themedark/theme!-- document encoding --!-- defaults to UTF-8 --encodingUTF-8/encoding!-- protocol for script and stylesheets --!-- defaults to https --protocolhttps/protocol!-- title of the document --documentTitle接口自动化测试报告/documentTitle!-- report name - displayed at top-nav --reportName接口自动化测试报告/reportName!-- report headline - displayed at top-nav, after reportHeadline --reportHeadline接口自动化测试报告/reportHeadline!-- global date format override --!-- defaults to yyyy-MM-dd --dateFormatyyyy-MM-dd/dateFormat!-- global time format override --!-- defaults to HH:mm:ss --timeFormatHH:mm:ss/timeFormat!-- custom javascript --scripts![CDATA[$(document).ready(function() {});]]/scripts!-- custom styles --styles![CDATA[]]/styles/configuration
/extentreportsStep-5配置系统
config下新建 MySystemInfo类继承 SystemInfo 接口
public class MySystemInfo implements SystemInfo {Overridepublic MapString, String getSystemInfo() {MapString, String systemInfo new HashMap();systemInfo.put(测试人员, zuozewei);return systemInfo;}
}可用于添加系统信息例如db的配置信息人员信息环境信息等。根据项目实际情况添加。
至此extentreports 美化报告完成。
Step-6添加测试用例
public class TestMethodsDemo {Testpublic void test1(){Assert.assertEquals(1,2);}Testpublic void test2(){Assert.assertEquals(1,1);}Testpublic void test3(){Assert.assertEquals(aaa,aaa);}Testpublic void logDemo(){Reporter.log(这是故意写入的日志);throw new RuntimeException(故意运行时异常);}
}Step-7测试用例suite
!DOCTYPE suite SYSTEM http://testng.org/testng-1.0.dtd suite name测试demo verbose1 preserve-ordertrueparameter namereport.config valuesrc/main/resources/report/extent-config.xml/parameter namesystem.info valuecom.zuozewei.extentreportdemo.config.MySystemInfo/test name测试demo preserve-ordertrueclassesclass namecom.zuozewei.extentreportdemo.testCase.TestMethodsDemo//classes/testlistenerslistener class-namecom.zuozewei.extentreportdemo.listener.MyExtentTestNgFormatter//listeners
/suite测试报告
HTML Resport 示例 Email Report 示例 工程目录 本文源码
https://github.com/7DGroup/Java-API-Test-Examples