在本文中,我将详细介绍如何将 ExtentReports 测试报告与TestNG集成。
主要特点:
TestNG 原生报告有点丑,信息整理有点乱。ExtentReports 是用于替换TestNG 原生报告。当然也可以使用 ReportNg,个人偏好 ExtentReports 样式。
官网已经给了很多demo了,大家可以参考练习,这里根据个人经验进行了配置。
引入pom.xml
<!--引入extentreports相关包-->
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.1.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>testng-extentsreport</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.relevantcodes</groupId>
<artifactId>extentreports</artifactId>
<version>2.41.2</version>
</dependency>
<!--引入testng测试框架-->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>compile</scope>
</dependency>
主要基于以下两项原因:
下载 ExtentReportes 源码,找到 ExtentTestNgFormatter 类,Listener 目录下创建 MyExtentTestNgFormatter.java 类直接继承 ExtentTestNgFormatter 类。
public class MyExtentTestNgFormatter extends ExtentTestNgFormatter {
构造方法加入
htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
具体代码如下:
ublic 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.GITHUB
htmlReporter.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.html
File reportFile=new File(reportPath, "report.html");
// 邮件报告名emailable-report.html
File 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 支持多种玩法
// 根据状态不同添加报告。型如警告
MyReporter.report.log(Status.WARNING, "接口耗时(ms):" + String.valueOf(time));
直接从TestClass 中运行时会报 MyReporter.report 的空指针错误,需做判空处理。
在测试集合 testng.xml 文件中导入 Listener 监听类。
<listeners>
<listener class-name="com.zuozewei.extentreportdemo.listener.MyExtentTestNgFormatter"/>
</listeners>
extent reporters支持报告的配置。目前支持的配置内容有title、主题等。 先在src/resources/目录下添加 config/report/extent-config.xml。
<?xml version="1.0" encoding="UTF-8"?>
<extentreports>
<configuration>
<timeStampFormat>yyyy-MM-dd HH:mm:ss</timeStampFormat>
<!-- report theme -->
<!-- standard, dark 个人喜好暗色 -->
<theme>dark</theme>
<!-- document encoding -->
<!-- defaults to UTF-8 -->
<encoding>UTF-8</encoding>
<!-- protocol for script and stylesheets -->
<!-- defaults to https -->
<protocol>https</protocol>
<!-- title of the document -->
<documentTitle>QA-接口自动化测试报告</documentTitle>
<!-- report name - displayed at top-nav -->
<reportName>QA-接口自动化测试报告</reportName>
<!-- report headline - displayed at top-nav, after reportHeadline -->
<reportHeadline>接口自动化测试报告</reportHeadline>
<!-- global date format override -->
<!-- defaults to yyyy-MM-dd -->
<dateFormat>yyyy-MM-dd</dateFormat>
<!-- global time format override -->
<!-- defaults to HH:mm:ss -->
<timeFormat>HH:mm:ss</timeFormat>
<!-- custom javascript -->
<scripts>
<![CDATA[
$(document).ready(function() {
});
]]>
</scripts>
<!-- custom styles -->
<styles>
<![CDATA[
]]>
</styles>
</configuration>
</extentreports>
config下新建 MySystemInfo类继承 SystemInfo 接口
public class MySystemInfo implements SystemInfo {
@Override
public Map<String, String> getSystemInfo() {
Map<String, String> systemInfo=new HashMap<>();
systemInfo.put("测试人员", "zuozewei");
return systemInfo;
}
}
可用于添加系统信息,例如:db的配置信息,人员信息,环境信息等。根据项目实际情况添加。 至此,extentreports 美化报告完成。
public class TestMethodsDemo {
@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("故意运行时异常");
}
}
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="测试demo" verbose="1" preserve-order="true">
<parameter name="report.config" value="src/main/resources/report/extent-config.xml"/>
<parameter name="system.info" value="com.zuozewei.extentreportdemo.config.MySystemInfo"/>
<test name="测试demo" preserve-order="true">
<classes>
<class name="com.zuozewei.extentreportdemo.testCase.TestMethodsDemo"/>
</classes>
</test>
<listeners>
<listener class-name="com.zuozewei.extentreportdemo.listener.MyExtentTestNgFormatter"/>
</listeners>
</suite>
2、Email Report 示例
五、工程目录
源码地址:
辑:桃子 时光
今天,斯坦福大学发布了2022年人工智能指数报告。
李飞飞教授在报告发布后第一时间转发。
今年的报告主要分为5大章节:研究及发展,技术表现,人工智能应用的道德挑战,经济和教育,人工智能政策和国家战略。
以下将为你提取7项报告要点:
过去的10年,全球AI论文发表量实现翻番,从2010年的162444篇增长到334497篇,且逐年递增。
具体而言,模式识别和机器学习领域的论文,仅2015年至2021年的6年间,就实现了倍增,其它诸如计算机视觉、数据挖掘和自然语言处理等领域,保持了比较平稳的发展。
另外,从论文的刊载情况来看,期刊文章占比最大,51.5%;21.5%是顶会论文,17.0%来自存储库。
可以看出,在过去12年中,期刊和储存库的论文分别增长了2.5倍和30倍,但顶会论文的数量自2018年以来有所下降。
论文跨国合作来看,从2010年到2021年,中国和美国共同发表的人工智能论文数量全球最多,自2010年以来就增加了5倍。中美合作的出版物数量是中英的2.7,世界排名第二。
2021年,中国在人工智能期刊、顶会和知识库出版物的数量上继续领先世界。这三种出版物类型的总和比美国高出63.2%。
与此同时,美国在人工智能顶会论文数量和存储库引用的数量上处于领先地位。
就AI期刊论文发表数量来看,过去12年人工智能期刊论文发表数量占比,中国始终霸榜,2021年为31.0%(2020年占比18.0%),其次是欧盟和英国,为19.1%,美国为13.7%。
2021年,中国在AI期刊的全球引用量依旧领先。
值得注意的是,不论是AI期刊论文发表数量、引用数量,美国从去年第2名降至第3名。
那么中美在顶会发表论文的情况如何?
2021年,中国以27.6%的比例在全球AI顶会发表的论文数所占份额最大,比2020年的领先优势更大,而欧盟和英国以19.0%紧随其后,美国以16.9%位居第3。
然而,美国一直在AI顶会论文引用量上居高不下,2021年引用总量占比29.52%,排名第2和第3的分别是欧盟英国(23.32%)和中国(15.32%)。
中国从去年第2名跌倒第3名,从侧面可以看出,中国论文发表数量最多,但质量不如美国高。
总体来看,2021年人工智能专利申请量是2015年的30多倍,年复合增长率为76.9%。
具体讲,中国申请了全球一半以上的AI专利,并获得了约6%的授权,与欧盟和英国大致相同。
与不断增长的人工智能专利申请和授权数量相比,中国的专利申请数量(2021年为87343件)远高于授权数量(2021年为1407件)。
从2015年至2021年GitHub开源AI软件库的用户数量可以看出,TensorFlow仍然是2021年最受欢迎的,GitHub累计星数约为161,000,比2020年略有增加。
排在第2名的便是OpenCV,紧随其后的是Keras、PyTorch 和 Scikit-learn
先来看一组照片,这展示了AI人脸识别水平的年序发展。
对比2014年,我们仅能将原本肤色表情丰富的真人,识别成一张黑白且模糊的人脸,但是到了2021年,计算机对黑色皮肤也能揭示更多细节,我们看到了图像人物皮肤的黑里带棕,以及表情的露齿带笑。
报告展示了计算机图像如何分类,下图包括飞机、自动汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车等各种类别,通过给定图像的分类模型与目标标签,提高了图像识别的智能化程度。
报告指出,随着深度学习运用于AI图像识别,图像识别的准确性有了很大提升。
以下是AI图像识别准确性的对比图,蓝色线条代表没有使用训练数据,绿色线条代表使用了训练数据。很明显,绿色线条(准确率99.02%)超越了蓝色线条(准确率97.9%),这意味着,AI图像识别经数据训练后准确性提高。
而无论是否使用深训练数据,AI图像识别(99.02%&97.90%)在2017年后均表现出了高于常人(94.9%准确率)的水平。
看来,「脸盲症」只存在于人类,AI几乎不会患。
报告使用了一份来自北京邮电大学的口罩人脸图片集,这6000个人脸识别数据集,提升了疫情期间人脸识别的准确率。
口罩遮挡住面部,这使得人脸识别系统收集到的面部信息大量减少,然而,来自中国的AI团队将人脸识别的关键信息集中于眉毛和眼睛,并采用正确的模型进行训练,实现了「戴着口罩也能刷脸」。
来看一下,计算机如何进行视觉常识推理的。
视觉常识推理,Visual Commonsense Reasoning(VCR)是AI领域的前沿热点问题,这是一项非常富有挑战的任务,包括认知、学习、推理,从单一的视觉问答、图像识别、动作捕捉等数据处理,上升到「跨媒体智能」,代表了计算机视觉理解的新基准。
报告指出,目前,计算机视觉常识推理能力远远落后于人类,人类的视觉常识推理水平一直维持在85分,而2021年机器的最佳得分只有72分。
看来,这确实有点Low,不过相较于2018年的不及格水平(43分),机器用3年时间提高了29分,显然是在大步向前了。
近年来,得益于语音识别技术的发展,完全机器翻译的服务应用大幅提升,占比46%。
相较于其它的应用,机器翻译的商业应用增速明显,商用规模从2019年的21%扩大到2021年的38%,近2倍。
报告使用了2015年由斯坦福大学Bowman等人提供的自然语言处理的问题和标签。
自然语言处理是在给定确定任务的前提下,假设4种逻辑,即错误(contradiction矛盾)、未决定(neutral中性)2种、是否为真(entailment蕴涵),机器对进行合理与不合理的推论。
报告显示,2021年自然语言处理的精准度已达93.1%,而在2017年初就已经达到90%,这是在高起点的基础上实现缓增长。
斯坦福自然语言推理(SNLI)数据集包含约60万对被标记的句子,其性能精度是基于答对问题的百分比。
从今年报告的总体体量上而言,较之于去年的7章,今年报告浓缩至5章,减少了「AI的多样性」部分,并将「AI经济」和「AI教育」合为「经济和教育」1章。
虽然总章数减少了,但是体量却变大了,目录页码由177页增加到了196页。
Burning Glass数据涵盖的六个国家对人工智能劳动力的需求在过去九年中显著增长。其中新加坡AI招聘岗位在总招聘岗位中占比2.33%,排名第一,美国0.90%排名第二。
就人工智能领域投资来讲,从2013年到2021年,美国对人工智能公司的私人投资是中国的2倍多。
中国的AI投资出现了增长,从2020年的10%上升到了2021年的17.21%。
报告下载地址:
https://aiindex.stanford.edu/wp-content/uploads/2022/03/2022-AI-Index-Report_Master.pdf
单页应用程序的概念正在寻找越来越多的支持者。最着名的单页框架之一是Angular,它是一个单页 的JavaScript应用程序框架。Angular的第一个版本基于JavaScript,但是所有后续版本都已经在使用TypeScript,并且与第一个版 本完全不同。在AngularJS上创建新应用程序没有任何意义,因此我们将使用当前版本的Angular 7。
Microsoft成功地将Angular和ASP结合起来。Net Core MVC。因此,使用ASP .Net Core MVC的实现 ,在单页面应用程序中显示报表相对容易。
Node.js安装
要在Angular框架上开始开发,您需要预先安装一个平台,以便在服务器端执行JavaScript代码。它 叫做Node.js。
您还需要安装.Net Core SDK 2.0或更新版本。但是,如果您安装了Microsoft Visual Studio 2017 ,则无需执行此操作。
如何创建应用程序?
有两种方法 - 在Visual Studio中创建新项目或从命令行运行命令。
对于第一个选项,您必须在Visual Studio扩展中安装Angular应用程序模板。
第二个更简单。为您的应用程序创建一个文件夹 在Windows命令行中,使用cd命令转到创建的文件 夹并执行以下命令:
dotnet new angular -o AngularFRCore
如您所知,AngularFRCore是项目的名称。创建应用程序后,您需要安装typescript库。我们将使用 Node.js npm平台库安装程序执行此操作。在控制台执行了创建应用程序的命令,在应用程序目录中运行另一个命令:
npm install -g typescript
现在,打开项目,没有解决方案文件,它将在您第一次启动项目时创建。
我们的演示应用程序的目标是展示如何在单页应用程序中使用FastReport.Core。让我们将 FastReport库添加到我们的项目中。打开NuGet包管理器。在右上角,您可以选择数据包的来源。我们对本地源感兴趣,但首先需要 配置它。为此,请单击右上角的齿轮图标。我们使用包设置本地文件夹的路径:
默认情况下,此文件夹是:C:\ Program Files(x86)\ FastReports \ FastReport.Net \ Nugets。
通过安装FastReport.Net,您可以获得上述包装中的现成包装。让我们回到包管理器:
现在有两个包,安装它们。 要在应用程序中使用FastReport,需要在Startup.cs文件中添加 一行代码:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { … app.UseFastReport(); …}
如果您浏览项目树,可以从MVC应用程序中看到我们熟悉的控制器和模型目录。可以使用几乎未改变 的MVC .Net Core应用程序作为后端。Controllers文件夹中已有一个 - SampleDataController。随意清除课程内容 - 我们将创建 自己的方法:
[HttpGet("[action]")] public IActionResult ShowReport(string name) { WebReport WebReport=new WebReport(); WebReport.Width="1000"; WebReport.Height="1000"; WebReport.Report.Load(String.Format("App_Data/{0}.frx", name)); // Load the report into the WebReport object System.Data.DataSet dataSet=new System.Data.DataSet(); // Create a data source dataSet.ReadXml("App_Data/nwind.xml"); // Open the xml database WebReport.Report.RegisterData(dataSet, "NorthWind"); // Registering the data source in the report ViewBag.WebReport=WebReport; // pass the report to View return View(); }
如果您已经熟悉FastReport.Core,那么此方法没有任何新内容。我们创建了Web报表对象,将报表 模板加载到其中,创建并注册了数据源并将报表传递给视图。此方法有一个参数 - 我们用于加载所需报表模板的报表的名称。
FastReport.Net集包含一个带有演示报表的文件夹:
C:\ Program Files(x86)\ FastReports \ FastReport.Net \ Demos \ Reports
我们将从中获取几个模板和一个nwind.xml数据库。但首先,在项目根目录中创建App_Data文件夹。 现在从上面的文件夹中将文件拖入其中:
Barcode.frx,Master-Detail.frx,Matrix.frx,nwind.xml。
下一步是为此方法创建一个视图。
我们的项目中没有Views文件夹。在项目根目录中创建它。在此文件夹中,添加另一个名为 SampleData的文件夹。最后,在此文件夹中,我们创建了一个新视图 - ShowReport.chtml,其中包含以下内容:
@await ViewBag.WebReport.Render()
在异步模式下,我们正在等待生成报表的HTML版本。
所以,我们准备了一个与Angular一起提供的后端。我们来看看ClientApp文件夹。这是一个单页的 应用程序。我们对src - > app目录感兴趣。以下是负责显示内容的主要文件 - 页面模板及其类型脚本处理程序。主页模板是 app.component.html。我们将完全编辑它:
FastReport.Core Demo Select a report and click the button Matrix Master-Detail Barcode
首先,我们为不同的报表显示三个单选按钮。每个按钮都订阅了Click事件,我们通过该事件设置报 表变量的值。该函数将报表的名称作为参数。通过这种方式,我们组织了所需报表模板的选择。这是一个相当原始的实现,但为了 演示报表,不再需要它。
下面,我们展示了一个名为ShowReport的按钮,它也使用Clicked()处理程序订阅了click事件。 注意条件* ngIf=“show”的div。如果show变量为true,则将执行内部变量中的代码。在我们的例子中,将显示框架。这样做是为 了在最初加载页面时不显示空框架。此外,当我们选择报告并单击“显示报表”按钮时,将显示包含报表的框架。
在框架属性中,我们从变量url设置源。有趣的是,我们在safeUrl函数的帮助下“规范化”这个变 量,并通过管道应用它。此函数将检查URL的安全性和有效字符,并将其显示为正确的格式。我们稍后会详细介绍它。
现在,查看app.component.ts组件脚本,该脚本负责处理上面讨论的模板:
import { Component } from '@angular/core'; @Component( { selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css']}) export class AppComponent { title='app'; show: boolean=false; url: string; report: string; Clicked() { if (this.report !=null) { this.show=true; this.url="api/SampleData/ShowReport?name=" + this.report; } }}
以下是我们在页面模板中看到的show和url变量。以及变量报表,其中包含所选报表的名称。 Clicked()函数将show变量设置为true,并在url变量中设置报表的路径。
现在我们将创建safeUrl函数,我们在管道中使用变量url。在app目录文件safeUrl.pipe.ts中:
import { Pipe, PipeTransform } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; @Pipe({ name: 'safeUrl' }) export class SafeUrlPipe implements PipeTransform { constructor(private sanitizer: DomSanitizer) { } transform(url) { return this.sanitizer.bypassSecurityTrustResourceUrl(url); }}
要在页面模板中使用此函数,请在app.module.ts中添加此管道模块的声明:
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { RouterModule } from '@angular/router'; import { SafeUrlPipe } from "./safeUrl.pipe"; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent, SafeUrlPipe ], imports: [ BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), HttpClientModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
这样就完成了演示应用程序的工作。运行应用程序:
首先,您需要选择其中一个报表,然后单击按钮:
现在选择另一个报表并单击按钮:
因此,您已经看到在Angular单页面应用程序中使用FastReport.Core报告生成器并不比通常的ASP .Net Core应用程序困难得多 。
*请认真填写需求信息,我们会在24小时内与您取得联系。