Erik Hatcher ([email protected])
eBlox 高级设计师
2001 年 8 月
极端编程(XP)主要原则的其中之一是程序员必须执行定期的单元测试,还必须不断的将变化集成到类似产品的环境中去。此外,XP 建议尽可能让这个过程自动化。毕竟,如果开发者像生产代码一样热切的创建测试案例,过程会相对的轻松些。
如果单元测试做的好的话,您应该会对每一段代码(特别是由个别类标明的)都能正常运行而满意。执行持续的或者不稳定的编译让您明白当代码集成到生产环境时它是如何生效的。在开发周期中集成单元测试和定期自动的编译,向您和您的客户保证了代码发布时是可靠的。
在本文中,我将为自动的编译和测试过程采取实用的方法。使用 Ant 1.3 和 JUnit 测试框架,将像您展示如何自动化一个过程,这个过程捕获每个测试套件运行的相关信息、生成有吸引力的报告并用电子邮件发送这个报告。虽然这些性能有许多隐含在 Ant 中,但我还是修改了许多核心任务来更好地满足要求。这些修改是本文的中心,它们将全部结合到 Ant 的下一个发行版中。可以在本文附带的源文件中找到所有补丁(请参阅参考文件)。您可能需要在阅读时回顾一下代码。此外,如果不熟悉 Ant 1.3,可能需要在继续这篇文章时学习官方的 Ant 文档(请参阅参考资料)。
为什么使用 Ant 和 JUnit?
Ant 1.3 是编译工具中的实际标准。由于用 Java 语言编写,Ant 是开放源代码的,可以在多种平台上运行,并为编译过程带来了很大的灵活性。JUnit 测试框架也是开放源代码的,它被广泛使用,并与 Ant 的编译过程集成(想学更多关于 Ant 和 JUnit 的知识,请参阅参考资料)。
Ant 1.3 加上可选的 <junit> 以及 <junitreport> 任务,不经修改就可以启动基本编译和测试的自动过程。这一过程如下:
运行 JUnit 测试实用程序 捕获测试结果 创建吸引人的 HTML 总结报告一旦捕获结果,就可以使用 XML 格式化器将每个测试套件运行的故障和错误数,连同软件包和类名还有测试套件的执行时间一起引入。对于每个测试套件,都有以下信息被捕获:
测试案例的名称 执行的持续时间 故障或错误的类型(如果适用) 任何故障或错误的详细信息这个构想中少了些什么
虽然功能上很完美,但上面描述的自动化既不理想也不完整。通过修改 JUnit 任务中的几个,我们可以创建按如下步骤运行的自动过程。
请给我更多数据
除了将 Ant 和 JUnit 扩展到能自动进行编译和测试的过程的程度外,我还添加了测试期间捕获的标准数据。即,我需要知道使用的是什么操作系统、测试的日期/时间、支持测试运行的 JVM 版本以及 classpath。
为捕获这个信息,我对 Ant 的 JUnit 相关类中的四个类:JUnitTask、JUnitTest、JUnitTestRunner 以及 XMLJUnitResultFormatter 做了简单修改。您会在附带的源文件中发现这些变化。
作为附带的优点,当扩展捕获的数据时,最终捕获的不仅是在测试套件运行时特定状态的信息,而且还包括了整个 Ant 的操作属性集。其中包含系统属性和内部 Ant 属性(例如用户定义的属性)。
让数据报告自动化
对 Ant 的 <junit> 任务进行扩展,使之能提供额外状态的信息之后,下一步就是启用自动化的数据报告。
使用 Ant 的最大优势之一是它的可扩展性。 对于使用带有 XML 格式化器(<formatter type="xml"/>)的 <junit> 任务运行的每个测试类,都创建了一个 XML 文件。<junitreport> 任务提供了一种很好的将所有收集的数据聚集到一起的方法。使用 XSLT,它会将测试数据转化为一种可以被轻松理解的 HTML 格式报告。
<junitreport> 可被轻松扩展,允许用户自定义的 XSLT 文件用作报告生成。XSLT 文件内建于 Ant 的 optional.jar 文件中。我将它和它必备的伴侣 toolkit.xsl 一起解压缩到本地目录,然后修改 overview_summary.xsl 文件以便将 Ant 属性引入报告。 而在 build.xml 中,我指定了“noframes”报告。在“测试套件”的相应部分中,添加到 overview_summary.xsl 中的代码断如清单 1 所示。
清单 1. overview_summary.xsl 代码段用以显示新添入的属性
<table> <xsl:for-each select="./Properties/Property"> <xsl:sort select="@name"/> <tr> <td><xsl:value-of select="@name"/></td> <td><xsl:value-of select="@value"/></td> </tr> </xsl:for-each> </table>
一旦修改了这些文件,您就可以运行编译。负责运行 JUnit 测试和创建 HTML 报告的 build.xml 代码段如清单 2 所示。
清单 2. build.xml 中用以运行 JUnit 测试和创建 HTMl 报告的部分
<target name="junit" depends="compiletests" description="Execute Unit Tests"> <junit> <formatter type="xml" /> <batchtest> <fileset dir="${build}"> <include name="test/**/*Test.class" /> </fileset> </batchtest> </junit> <junitreport> <fileset dir="."> <include name="TEST-*.xml"/> </fileset> <report format="noframes" styledir="etc/xsl"/> </junitreport> </target>
关于这个编译代码段,您应该注意的主要事情是 <junitreport> 中 <report> 元素的 styledir 属性;它指定了用户自定义的 XSLT 文件所在的目录。为捕获日期/时间戳,您需要在 build.xml 某处的 <junit> 任务前引入 <tstamp> 任务。
让电子邮件任务自动化
Ant 有一个内建的 <mail> 任务,但不幸的是这个任务只有文本消息的性能,不能处理文件附件。 但最近,一项任务被提交到 Ant 开发组,它实现了 MIME 邮件的性能。
我和另两个积极的 Ant 开发者一起工作,改善这个最近提交的任务,这样它就可以支持 Ant 的 FileSet 特性以及抄送和暗送的邮件功能。我还添加了另一个很好的特性 — 将文件附加到电子邮件消息正文的能力。
现代的电子邮件阅读器可以像 MIME 那样显示附带的 HTML 内容,还可以像浏览器那样解读 HTML 代码。图 1 显示了使用 <mimemail> 任务、用 Ant 发送的 JUnit 报告电子邮件样本是什么样子。
图 1. 用 Ant 发送的 JUnit 报告样本
发送电子邮件的代码如清单 3 所示。
清单 3. build.xml 中用来发送电子邮件的代码段
<target name="mail"> <taskdef name="mimemail" classname="org.apache.tools.ant.taskdefs.optional.mail.MimeMail"/> <tstamp/> <mimemail messageMimeType="text/html" messageFile="overview-summary.html" tolist="[email protected]" mailhost="mail.eblox.com" subject="JUnit Test Results: ${TODAY}" from="[email protected]"> <fileset dir="."> <include name="TESTS-*.xml"/> </fileset> </mimemail> </target>
代码注释:
<taskdef> 用来定义 <mimemail> 任务,因为现在 Ant 没有提供这个功能。以后,这个任务可能会成为 Ant 的可选任务之一;那么 <taskdef> 就会成为多余。排障、测试和部署
我为 Ant 开发团体提供了刚才讨论的所有的代码修正,他们已经认可将其包含到以后的发行版中去。但是,因为官方的 Ant 发行版还没有包含这篇文章中使用的技巧,在让这些技巧为您服务之前还需要采取一些措施。
让代码生效
第一,这些代码的修正是基于 Ant 1.3 发行版的;这是我将推荐的用于这代码的唯一 Ant 版本。 提供的代码包含了 JUnitMail.jar 和用于生成 jar 文件的源代码。这个 jar 文件必须存在于启动 Ant 环境中的 classpath 里 — 在 Ant 的 optional.jar 之前。
如果您是个典型的 Ant 用户,您通过 $ANT_HOME/bin 中的包装脚本之一运行 Ant。这些包装脚本在启动 Ant 前将所有 $ANT_HOME/lib 中的 jar 文件放入 classpath。在 Windows 平台下只要将 JUnitMail.jar 放入 $ANT_HOME/lib 目录,用 ant.bat 就可以处理 classpath 问题。
如果遇到过古怪的行为(例如,也许从 <junit> 捕获的额外参数没有在 XML 文件中出现),那么就调试在包装脚本中用到的 classpath(例如,ant.bat 中的 %LOCALCLASSPATH% )并修改包装脚本,确保 classpath 中 JUnitMail.jar 在 optional.jar 之前。
测试代码
在将这新的代码集成到 classpath 中以后,用 XML 格式化器测试一个简单的 JUnit 测试示例(如清单 2 所示)确保捕获了额外的 Ant 属性。
额外属性作为 <Property> 元素在 XML 格式化器中被捕获。如果,由于某种原因致使属性元素没有出现,就可能是一个 classpath 的问题。
确保修正后的 JUnit 任务正在被使用,一个保险的办法是使用我的 JUnitMail.jar 版本中提供的 JUnitTask.class、JUnitTest.class、JUnitTestRunner.class 和 XMLJUnitResultFormatter.class 来代替 optional.jar 中相应的文件。
<mimemail> 任务有两个依赖条件 — JavaMail 和 Java 活动框架(请参阅参考资料)。在启动 Ant 时,这两个 jar 文件必须放在 classpath 中,以便使用 <mimemail>。
定制布局
您可以通过调整 XSLT 文件定制 JUnit 结果的 HTML 布局。我通过为每个测试套件在隐藏的 <DIV> 中添加额外属性以及添加一些用于隐藏及显示该额外信息的 JavaScript 的方法修改了 Ant 的标准布局。这些 JavaScript 技巧可以在 Internet Explorer 中生效,但在 Netscape 中不起作用(它显示了所有的属性,没有隐藏)。
我添加新捕获属性的首要目的仅仅是让那些信息可用,不过将这些属性结合到 HTML 报告中的方法,还有很大的改进余地。(请记住,如果您做了任何改进,请将之提交到 Ant 开发者和用户团体,让我们大家分享!)
让 XP 成真
一旦您使用了我的补丁,让编译和测试过程自动进行只是个在 cron 作业(或者是 Windows 平台上的 at 作业)中包装 Ant 执行的问题。
理想化的想法是,自动进行的过程将会把代码从您的源代码管理系统中提取出来,完成编译、执行单元测试、然后每晚用电子邮件发送结果。还有将整个编译日志捕获并用电子邮件发送或张贴到 intranet 站点,这样您就与“持续集成”和 XP 梦想接近了一步。
参考资料
请参与有关本文的讨论论坛。
您会在这个压缩文件中找到所有 Ant 的 JUnit 任务和新的 MimeMail 任务的补丁, 以及增强的 XSL 文件。
请从 Jakarta project 下载 Ant 1.3。
如果直到今天您仍没有(使用 JUnit)测试代码,现在机会来了。
若要开始合并 Ant/JUnit(包括如何创建 JUnit 测试案例),请阅读 Malcolm Davis 的“Incremental development with Ant and JUnit”(developerWorks,2000 年 11 月)。
出色的文章,“Ant in Anger,”描述了 Ant 在典型的产品开发环境下的使用。
请尝试极端编程站点以获取更多这个主题的信息。
JavaMail 和 Java 活动框架是 <mimemail> 任务必需的。
Ant 和 JUnit 是对 WebSphere 应用开发环境的完美的测试赞美辞;版本 4.0 提供了增强的扩展,例如 Java 业务规则,使得不必重写代码就可以改变 Java 应用。
需要企业级的系统测试的帮助,请看 IBM Performance Management, Testing and Scalability Services 提供了些什么(包含一个有关企业测试的库,PDF 格式)。
请在 developerWorks Java 技术专区查找更多 Java 参考资料。
本文地址:http://com.8s8s.com/it/it13577.htm