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"/>

定制测试报告,有两种方法:

  1. XSLT 文件内建于 Ant 的 optional.jar 文件中。将它解压缩到本地目录,然后修改 junit-frames.xsl 文件以便将 defect 信息引入报告。
  2. 创建一个自定义的 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相关推荐

  1. Vi,Java,Ant,Junit的自学报告

    Vi,Java,Ant,Junit,SonarQube的自学报告 Vi/Vim 参考资料:<鸟哥的Linux私房菜> 为什么在Linux的世界中选择vi,vim 可以快速地在终端中编辑属于 ...

  2. Java Annotation

    为什么80%的码农都做不了架构师?>>>    第1部分 Annotation架构 先看看Annotation的架构图: 从中,我们可以看出: (01) 1个Annotation 和 ...

  3. Java Annotation认知(包括框架图、详细介绍、示例说明)

    摘要 Java Annotation是JDK5.0引入的一种注释机制. 网上很多关于Java Annotation的文章,看得人眼花缭乱.Java Annotation本来很简单的,结果说的人没说清楚 ...

  4. java 数据校验框架_自己写的基于java Annotation(注解)的数据校验框架

    JavaEE6中提供了基于java Annotation(注解)的Bean校验框架,Hibernate也有类似的基于Annotation的数据校验功能,我在工作中,产品也经常需要使 用数据校验,为了方 ...

  5. Java Build工具Ant与Maven之比较

    Java Build工具Ant与Maven之比较 阅读协议:我首先声明本文为翻译文章.译者--我--并不一定认可本文原作者的观点,同时也不保证译者能正确地.清楚地表达出原作者的思想.凡是读者因看了本文 ...

  6. java+构建+工具+Ant+Maven+Gradle

    java+构建+工具+Ant+Maven+Gradle Ant+Maven+Gradle+............ 目前: Ant已经销声匿迹.Maven也没落了,而Gradle的发展则如日中天. M ...

  7. 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 ...

  8. Java Annotation的RetentionPolicy介绍

    Java Annotation对应的Retention有3种,在RetentionPolicy中定义,有3种: SOURCE. 注解保留在源代码中,但是编译的时候会被编译器所丢弃.比如@Overrid ...

  9. java annotation应用_Java Annotation高级应用

    前言: 在此行文<java annotation高级应用>,具体实例化解释annotation和annotation processing tool(APT)的使用.望能对各位的有所帮助. ...

  10. JAVA Junit error java.lang.SecurityException: class junit.framework.JUnit4TestCaseFacade

    运行junit4时报错: java.lang.SecurityException: class "junit.framework.JUnit4TestCaseFacade"'s s ...

最新文章

  1. MySQL等值传播(low!就是一层窗户纸)
  2. 一个平行四边形可以分成四个_【八年级下】数学 平行四边形(3)菱形
  3. OSSIM中快速部署HIDS
  4. nginx ngx_http_proxy_module(反向代理)
  5. 服务和服务帐户安全规划指南
  6. UIcollectionView 加入尾部视图
  7. LOL登录后黑屏,主界面一直加载解决办法
  8. 小米盒子3增强版 android,小米盒子3增强版拆机评测 怎么样?好不好?
  9. 【第七篇】Flowable核心内容之任务分配
  10. 虚拟机安装python3_虚拟机如何安装python
  11. uni-app 超好用的时间选择器组件(起止时间)
  12. 【前端面试题】原型和原型链-js
  13. 《你好,数智新世界》系列访谈 对话数睿数据总裁刘超|企业级无代码赋能软件产业变革...
  14. 用MVC写的查询,添加,删除,修改,登录。
  15. 数据库中冗余数据处理_SQL去重
  16. stm32小车红外对管的循迹
  17. 【每日早报】2019/10/21
  18. 泛微9.0明细表必填规则
  19. 使用C#编写一个读取和判断股票实时成交数据的小工具
  20. 留一法(Leave-One-Out)与确定性

热门文章

  1. selenium3下打不开Firefox报错解决
  2. 沫沫金:EasyUI 固定列
  3. Android的代码同步repo
  4. [转载] 民兵葛二蛋——第7集
  5. Conditional GET Request(缓存协商)
  6. openmeeting开发心得及相关文档
  7. Devexpress使用记录
  8. Spring使用XML的方式实现AOP的开发——Spring AOP(六)
  9. [Java][Android][Process] Process 创建+控制+分析 经验浅谈
  10. [2018.10.23 T1] 战争