使用 Java Annotation 定制 Ant Junit Report
JUnit 和 Ant
JUnit 是一个开源的 Java 测试框架,可以帮助开发人员简化测试案例的编写,已成为 Java 社区中知名度很高的单元测试工具。
Apache Ant 是一个基于 Java 的构建工具,它凭借出色的易用性、平台无关性以及对项目自动测试和自动部署的支持,成为众多项目构建过程中不可或缺的工具,并已经成为事实上的标准。大多数现代 Java IDE(包括 Eclipse)都支持 Ant 构建文件的开发,也都支持在 IDE 内部运行这些文件;而 Ant 也可以独立于任何 IDE 运行。
Ant 内置了对 JUnit 的支持,它提供了两个 Task:junit 和 junitreport,分别用于执行 JUnit 单元测试和生成测试结果报告。测试人员使用生成的测试结果报告,可以很方便地查看并分析测试结果。下图为 Ant 生成的 HTML 格式的测试结果报告。
图 1. Ant 生成的 HTML 格式的测试结果报告
(查看图 1 的 清晰版本。)
回页首
在测试结果报告中缺了什么?
在生成的测试结果报告中,可以看到每个测试套件的软件包和类名、测试案例的故障和错误数,以及测试套件的执行时间。对于每个测试套件,可以看到如下信息:
- 测试案例的名称
- 测试结果
- 故障或错误的类型(如果适用)
- 任何故障或错误的详细信息
- 执行的持续时间
但是,我们无法在上述测试结果报告中看到测试案例相对应的 Defect(缺陷)信息。这个信息在用户查看并分析测试结果报告的时候至关重要:
- 对于成功的测试案例,用户可以看到它的 defect 历史信息;
- 对于失败的测试案例,用户可以很快知道这个失败的测试案例有没有对应的 defect;
- 对于新失败的测试案例,用户可以方便知道是不是产生了 regression defect;
回页首
扩展 Ant JUnit Report
为了在测试结果报告中添加测试案例相对应的 defect 信息,下面将介绍如何利用 Java Annotation,并扩展 Ant 来实现这个目标。
使用 Annotation 定义 defect 信息
首先,需要定义一个 Annotation 表示 defect,并给测试案例加上这个 annotation。
清单 1. 定义一个 annotation: Defect
import java.lang.annotation.Target; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.ElementType; import java.lang.annotation.RetentionPolicy; @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @Interface Defect { public String value(); } |
定义好了 Defect annotation 后,用 defect annotation 给测试案例加上相对应的 defect(如果有的话)。
清单 2. 给测试案例加上 defect annotation
@Defect(“DDDL7Z76CX”) public void testRenameDocumentChangingExtension() throws Exception { //test logic here } |
扩展 XML 结果格式化器
Ant 的最大优势之一是它的可扩展性。对于使用带有 XML 格式化器( <formatter type="xml"/> )的 <junit> 任务运行的每个测试类,都创建了一个 XML 文件。
为了捕获测试案例对应的用 annotation 定义的 defect 信息,我们需要扩展 Ant 的 JUnit 相关类中的 XMLJUnitResultFormatter 来添加 defect 信息。 XMLJUnitResultFormatter 类中添加的部分用 /*-- ADDED --*/ 标明。
清单 3. XMLJUnitResultFormatter 中的修改部分
/** * Interface TestListener. * * A Test is finished. * @param test the test. */ public void endTest(Test test) {if (!testStarts.containsKey(test)) {startTest(test);}Element currentTest = null;if (!failedTests.containsKey(test)) {currentTest = doc.createElement(TESTCASE);String n = JUnitVersionHelper.getTestCaseName(test);currentTest.setAttribute(ATTR_NAME,n == null ? UNKNOWN : n);// a TestSuite can contain Tests from multiple classes,// even tests with the same name - disambiguate them.currentTest.setAttribute(ATTR_CLASSNAME,JUnitVersionHelper.getTestCaseClassName(test));/*-- ADDED --*/ // 获取defect信息Method method = null;try{method = test.getClass().getMethod(n, new Class [0]);}catch (SecurityException e){e.printStackTrace();}catch (NoSuchMethodException e){e.printStackTrace();}boolean hasDefect = method.isAnnotationPresent(DefectAnnotation.Defect.class);//若有defect信息,添加到生成的XML文件if (hasDefect){Defect defectAnnotation = (Defect)method.getAnnotation(DefectAnnotation.Defect.class);String defectNumbers = defectAnnotation.value();currentTest.setAttribute("defects",defectNumbers);}/*-- END ADDED --*/rootElement.appendChild(currentTest);testElements.put(test, currentTest);} else {currentTest = (Element) testElements.get(test);}Long l = (Long) testStarts.get(test);currentTest.setAttribute(ATTR_TIME,"" + ((System.currentTimeMillis()- l.longValue()) / ONE_SECOND));} |
作为附带的优点,当扩展捕获的数据时,最终捕获的不仅是在测试套件运行时特定状态的信息,而且还包括了用户自定义的属性。这样,在生成的 XML 文件中就会包含测试案例对应的 defect 信息。
使用自定义的 XSLT 在生成的测试结果报告中显示 defect
junitreport task 使用 XSLT 把 junit task 生成的 xml 文件生成 HTML 格式的测试结果报告。<junitreport> 可被轻松扩展,允许用户自定义的 XSLT 文件用作报告生成。我们可以在 <junitreport> 中嵌套的 <report> 标签中用“styledir”属性指定用户自定义的 XLST 文件所在的目录。
<!-- 使用 reportstyle/junit-frames.xsl 生成测试报告 --> <report styledir="reportstyle" format="frames" todir="testreport"/> |
定制测试报告,有两种方法:
- XSLT 文件内建于 Ant 的 optional.jar 文件中。将它解压缩到本地目录,然后修改 junit-frames.xsl 文件以便将 defect 信息引入报告。
- 创建一个自定义的 XSLT 文件,然后在 <junitreport> 中嵌套的 <report> 标签中用“styledir”属性指定用户自定义的 XLST 文件所在的目录。对于一些小的修改,创建一个自定义的 XSLT 文件,引入默认的 XSLT, 并且覆盖需要定制的 templates 是一个不错的方法。例如,在每一个测试案例中加一列(defect 信息), 我们就只需要重载产生表头和表行的 template 就可以了。
在下面的清单中,是重载产生表头和表行来加 defect 的例子(添加的部分用 <!-- ADDED --> 标明)。
清单 4. 自定义的 XSLT
<xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><!-- import the default stylesheet --> <xsl:import href="jar:file:lib/ant-junit.jar!/org/apache/tools/ant/taskdefs/optional/junit/xsl/junit-frames.xsl"/> <!-- override the template producing the test table header --> <!-- method header --> <xsl:template name="testcase.test.header"> <xsl:param name="show.class" select="''"/> <tr valign="top"> <xsl:if test="boolean($show.class)"> <th>Class</th> </xsl:if> <th>Name</th> <th>Status</th> <th width="80%">Type</th> <!-- ADDED --> <th width="80%">Defects</th> <th nowrap="nowrap">Time(s)</th> </tr> </xsl:template> <!-- override the template producing a test table row --> <xsl:template match="testcase" mode="print.test"> <xsl:param name="show.class" select="''"/> <tr valign="top"> <xsl:attribute name="class"> <xsl:choose> <xsl:when test="error">Error</xsl:when> <xsl:when test="failure">Failure</xsl:when> <xsl:otherwise>TableRowColor</xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:variable name="class.href"> <xsl:value-of select="concat(translate(../@package,'.','/'), '/', ../@id, '_', ../@name, '.html')"/> </xsl:variable> <xsl:if test="boolean($show.class)"> <td> <a href="{$class.href}"> <xsl:value-of select="../@name"/> </a> </td> </xsl:if> <td> <a name="{@name}"/> <xsl:choose> <xsl:when test="boolean($show.class)"> <a href="{concat($class.href, '#', @name)}"> <xsl:value-of select="@name"/> </a> </xsl:when> <xsl:otherwise> <xsl:value-of select="@name"/> </xsl:otherwise> </xsl:choose> </td> <xsl:choose> <xsl:when test="failure"> <td>Failure</td> <td> <xsl:apply-templates select="failure"/> </td> </xsl:when> <xsl:when test="error"> <td>Error</td> <td> <xsl:apply-templates select="error"/> </td> </xsl:when> <xsl:otherwise> <td>Success</td> <td></td> </xsl:otherwise> </xsl:choose> <td> <!-- ADDED --> <xsl:call-template name="display-defects"> </xsl:call-template> </td> <td> <xsl:call-template name="display-time"> <xsl:with-param name="value" select="@time"/> </xsl:call-template><!-- ADDED --> <xsl:template name="display-defects"> <xsl:choose> <xsl:when test="not(@defects)">N/A</xsl:when> <xsl:otherwise> <xsl:value-of select="@defects"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> |
部署
以上整个工作只涉及到修改一个现有的类 (XMLJunitResultFormatter.java),添加一个新的类 (DefectAnnotation.java) 并创建一个自定义的 XSLT 文件,之后就可以开始部署的工作(这些文件可以在下载的 zip 包中看到)。将修改之后的类文件编译好,连同自定义的 XSLT 文件打包到 Ant-Junit.jar 中去替代原有的 class 就可以了。
为了使用这个新的 Ant-Junit.jar,可以拷贝新的 Ant-Junit.jar 到 Ant\lib 目录中,也可以在运行 Ant 的时候,用 -lib 参数来指定你的新 Ant-Junit.jar 。这样,就可以在生成的测试结果报告中看到测试案例对应的 defect 信息了。
包含 defect 信息的测试结果报告如下。
图 2. 包含 defect 信息的 Ant JUnit Report
(查看图 2 的 清晰版本。)
转载于:https://www.cnblogs.com/mengheyun/archive/2011/02/15/1955502.html
使用 Java Annotation 定制 Ant Junit Report相关推荐
- Vi,Java,Ant,Junit的自学报告
Vi,Java,Ant,Junit,SonarQube的自学报告 Vi/Vim 参考资料:<鸟哥的Linux私房菜> 为什么在Linux的世界中选择vi,vim 可以快速地在终端中编辑属于 ...
- Java Annotation
为什么80%的码农都做不了架构师?>>> 第1部分 Annotation架构 先看看Annotation的架构图: 从中,我们可以看出: (01) 1个Annotation 和 ...
- Java Annotation认知(包括框架图、详细介绍、示例说明)
摘要 Java Annotation是JDK5.0引入的一种注释机制. 网上很多关于Java Annotation的文章,看得人眼花缭乱.Java Annotation本来很简单的,结果说的人没说清楚 ...
- java 数据校验框架_自己写的基于java Annotation(注解)的数据校验框架
JavaEE6中提供了基于java Annotation(注解)的Bean校验框架,Hibernate也有类似的基于Annotation的数据校验功能,我在工作中,产品也经常需要使 用数据校验,为了方 ...
- Java Build工具Ant与Maven之比较
Java Build工具Ant与Maven之比较 阅读协议:我首先声明本文为翻译文章.译者--我--并不一定认可本文原作者的观点,同时也不保证译者能正确地.清楚地表达出原作者的思想.凡是读者因看了本文 ...
- java+构建+工具+Ant+Maven+Gradle
java+构建+工具+Ant+Maven+Gradle Ant+Maven+Gradle+............ 目前: Ant已经销声匿迹.Maven也没落了,而Gradle的发展则如日中天. M ...
- Error:java: Annotation processing is not supported for module cycles. Please ensure that all modules
Error:java: Annotation processing is not supported for module cycles. Please ensure that all modules ...
- Java Annotation的RetentionPolicy介绍
Java Annotation对应的Retention有3种,在RetentionPolicy中定义,有3种: SOURCE. 注解保留在源代码中,但是编译的时候会被编译器所丢弃.比如@Overrid ...
- java annotation应用_Java Annotation高级应用
前言: 在此行文<java annotation高级应用>,具体实例化解释annotation和annotation processing tool(APT)的使用.望能对各位的有所帮助. ...
- JAVA Junit error java.lang.SecurityException: class junit.framework.JUnit4TestCaseFacade
运行junit4时报错: java.lang.SecurityException: class "junit.framework.JUnit4TestCaseFacade"'s s ...
最新文章
- MySQL等值传播(low!就是一层窗户纸)
- 一个平行四边形可以分成四个_【八年级下】数学 平行四边形(3)菱形
- OSSIM中快速部署HIDS
- nginx ngx_http_proxy_module(反向代理)
- 服务和服务帐户安全规划指南
- UIcollectionView 加入尾部视图
- LOL登录后黑屏,主界面一直加载解决办法
- 小米盒子3增强版 android,小米盒子3增强版拆机评测 怎么样?好不好?
- 【第七篇】Flowable核心内容之任务分配
- 虚拟机安装python3_虚拟机如何安装python
- uni-app 超好用的时间选择器组件(起止时间)
- 【前端面试题】原型和原型链-js
- 《你好,数智新世界》系列访谈
对话数睿数据总裁刘超|企业级无代码赋能软件产业变革...
- 用MVC写的查询,添加,删除,修改,登录。
- 数据库中冗余数据处理_SQL去重
- stm32小车红外对管的循迹
- 【每日早报】2019/10/21
- 泛微9.0明细表必填规则
- 使用C#编写一个读取和判断股票实时成交数据的小工具
- 留一法(Leave-One-Out)与确定性
热门文章
- selenium3下打不开Firefox报错解决
- 沫沫金:EasyUI 固定列
- Android的代码同步repo
- [转载] 民兵葛二蛋——第7集
- Conditional GET Request(缓存协商)
- openmeeting开发心得及相关文档
- Devexpress使用记录
- Spring使用XML的方式实现AOP的开发——Spring AOP(六)
- [Java][Android][Process] Process 创建+控制+分析 经验浅谈
- [2018.10.23 T1] 战争