利用Ant使测试自动化 如前面所述,测试运行器是非常原始的。如果你正在运行Ant来编译你的工程,那么编译文件是运行单元测试的好方法。(关于Ant的介绍,请参考我的文章《Ant简介》(Starting with Ant),发表于Oracle杂志2002年11/12月号中)。 假设你的源文件在src目录中,所生成的类在tmp目录中,并且junit.jar库位于工程的libdirectory目录中,那么你可以编译Java源文件,并使用清单3中所示的编译文件(在工程的根目录中)运行单元测试。 这个编译文件的核心是运行单元测试的测试目标。运行这些测试是这个目标junit的唯一任务。为了运行这一可选任务,必须首先将junit.jar库放到Ant安装目录下的lib目录中,然后下载并安装同一目录中的Ant可选任务库。清单3中的示例嵌套了一个classpath类,它包括JUnit库和工程的类;示例中还嵌套了一个batchtest元素,它利用一个选择适当源文件的fileset元素定义了将要运行的测试。这个任务还包括haltonfilure和haltonerror属性,它们告诉Ant在遇到一个失败或错误时是否应当停止。如果将它们的值设置为"真",那么Ant在遇到第一个失败或错误时将会停止,编译将会失败(显然,这表示在运行测试过程中存在有问题)。另一方面,如果将它们的值设置为"假",其结果就不是非常明确了(即使测试失败,编译也会成功),但所有测试仍将运行。printsummary属性指示Ant是否显示运行测试的输出。数值withOutAndErr可以在开发测试时方便地告诉Ant显示标准输出和错误输出。数值off表示不显示任何内容,而on只显示测试报告(没有测试类的输出)。junit任务具有很多属性,详细内容请参考Ant的文档。 为了测试这一编译文件,你需要建立名字为src、tmp和lib的目录。将junit.jar库放到lib目录中,并将前面看到的示例Java源文件放到src目录中。打开终端,进入该工程的根目录,并输入ant,其结果为: $ ant
Buildfile: build.xml
clean:
[delete] Deleting directory
/Users/casa/doc/oracle
/junit/prj/tmp
[mkdir] Created dir: /Users/casa
/doc/oracle/junit/prj/tmp
bin:
[javac] Compiling 4 source files
to /Users/casa/doc/oracle
/junit/prj/tmp
test:
[junit] Running IsoDateTest
[junit] Tests run: 1, Failures:
0, Errors: 0, Time elapsed:
0,005 sec
[junit] Running IsoDateTest2
[junit] Tests run: 2, Failures: 0,
Errors: 0, Time elapsed: 0,031 sec
[junit] Output:
[junit] setUp()
[junit] testIsoDate()
[junit] tearDown()
[junit] setUp()
[junit] testToString()
[junit] tearDown()
all:
BUILD SUCCESSFUL
Total time: 8 seconds
Ant还可以生成非常有用的HTML格式的测试报告。为了生成这样的报告,将前面的测试目标用以下目标代替: <target name="test" depends="bin"
description="Run JUnit tests">
<junit haltonfailure="false"
printsummary="withOutAndErr">
<classpath refid="cp"/>
<batchtest todir="${tmp}">
<fileset dir="${src}"
includes="**/*Test*.java"/>
</batchtest>
<formatter type="xml"/>
</junit>
<junitreport todir="${tmp}">
<fileset dir="${tmp}"
includes="TEST-*.xml"/>
<report format="frames"
todir="${tmp}"/>
</junitreport>
</target>
这一目标与前面的目标相同,只是该目标在batchtext元素中增加了一个新的属性--todir,它告诉Ant在tmp目录中生成可扩展的标记语言(XML)报告。该目标还增加了一个新的junitreport元素,以便由XML文件生成一个HTML报告。这一元素要求在安装Ant的lib目录中安装Xalan库(详细内容见Ant文档的junitreport部分:ant.apache.org/manual/install.html)。这一元素还定义了使用todir属性生成的文件的目标目录。通过嵌套一个fileset元素来定义为生成这一报告而需要处理的XML文件。期望的输出格式利用嵌套的报告元素来实现。该对象将生成一个诸如图4所示的报告。 这类报告在使单元测试自动运行时特别有用(比如在夜间编译期间)。在这些情况下,错误或失败不会中断测试,因此你必须将前面提到的junit任务的haltonfailure和haltonerror属性设置为"假"。这一报告对于衡量实施进程也非常有用(比如当你必须重写已有代码时,或者在实施之前已经编写了测试的情况下)。 Ant对启动JUnit图形运行器也非常有用。下面的对象将会启动Swing测试运行器: <target name="testui" depends="bin"
description="Run graphical JUnit">
<java classname="junit.swingui.TestRunner"
classpathref="cp"
fork="true"/>
</target>
你应当在终端中运行这一对象,并且在另一个终端或你喜欢的IDE中使用Ant对其进行编译。这种方式使你不必在每次想要测试代码时都启动图形运行器。 在Oracle9i Jdeveloper中的JUnit集成 Oracle9i JDeveloper并没有基于网络集成JUnit,但是下载并安装这一插件只需要几分钟的时间。为了完成此过程,选择JDeveloper的"Help"菜单下的"Check for Updates"项。这样将会打开IDE更新向导,以连接到Oracle技术网站,下载该插件并安装它。当安装该插件后,需要关闭并重启Oracle9i JDeveloper。注意,向导还会下载相关的文档。 通过为每个任务提供向导,这个插件极大地提高了开发人员编写测试实例、测试包和fixture等的工作效率。要调用这些向导,点击"File"菜单下的"New"项,然后选择"General/Unit Tests"类,并从右侧的窗体中选择合适的向导。你也可以从界面上启动测试套件。 当准备好对项目进行代码测试后,应当首先使用专用向导来编写fixture,然后测试实例向导可以利用它们集成到测试实例中。另外,还有一些用来生成自定义测试fixture的向导以及生成商务组件和数据库连接测试fixture的向导。这后两种向导生成专用代码,以使用setUp()和tearDown()方法设置和发布商务组件或数据库连接。 当完成fixture后,下一步应当使用合适的向导来生成测试实例,这些向导可以让你选择要测试的类和方法。你还可以选择在这个测试中使用的fixture。这将生成一个使用测试方法的主体完成的代码框架。最后应当生成套件来运行你的测试。这个专用向导让你选择要包括在套件中的测试,并为你生成整个类。要启动一个测试套件,点击浏览器中的文件,并选择Run。这将会启动图形界面并运行套件的测试。 在"Help"菜单中选择"Help Topics",你将会在JDeveloper文档中找到关于如何使用这些向导的详细教程。这会打开帮助系统窗口。点击"Unit Testing with JUnit"项,然后选择合适的教程。 JUnit和JDeveloper之间的这种集成使你能够只编写单元测试中你感兴趣的那部分的代码,而让工具为你编写重复的代码。
JUnit最佳实践 下面是一些在使用JUnit时应当注意的技巧:
- 在实施之前编写测试代码。这是一种合同驱动的实施方式。
- 只测试那些可能会中断的方法(也就是说,在多数情况下不应测试setter和getter方法)。要尽可能地多进行测试,以避免回归测试。当测试一个较大的应用程序时,你可以在夜间编译时运行所有测试。
- 一定要使用正确的JUnit扩展来测试特殊的应用程序(如使用Castus测试J2EE应用程序)。
值得花费的时间 到现在,你应当已经清楚地知道使用JUnit框架和合适的工具实施单元测试是多么快速而简单。关于单元测试的下一个目标是使你的CTO相信你在实施测试时所必须花费的时间是为了以后节省更多的时间。但是,当你考虑在检查老代码、修正错误和发布一个调试过的版本上所花费的时间(它可能花费整个一天)时,在开发过程的早期阶段捕获的代码错误毫无疑问是一项很好的投资。这里并没有考虑当错误代码不再位于块的顶部时开发人员必须遵循的"black magic"步骤,这些步骤包括:标记代码,制作一个分支、修正代码错误、进行发布,以及将代码修正合并到块中。所有这些步骤都非常耗时,并且容易产生错误。 要开始使用单元测试和JUnit,请访问JUnit网站: www.junit.org。你将找到大量有用的文档(包括使用JUnit实施测试的详细说明书)、一个与JUnit集成的IDE列表,以及关于JUnit扩展工具的详细内容。 Michel Casabianca ( casa@sweetohm.net)是In-Fusio(一家为移动用户提供游戏服务的法国公司)的一名软件工程师,同时也是XML Pocket Reference(O'Reilly出版,2001年)一书的合著者。
表1:编写测试实例中所使用的判定方法
| assertEquals(期望原型,实际原型) | 检查两个原型是否相等 | assertEquals(期望对象,实际对象) | 利用对象的equals()方法检查两个对象是否相等 | assertSame(期望对象,实际对象) | 检查具有相同内存地址的两个对象是否相等 | assertNotSame(期望对象,实际对象) | 检查具有不同内存地址的两个对象是否不相等 | assertNull(对象 对象) | 检查一个对象是否为空 | assertNotNull(对象 对象) | 检查一个对象是否为非空 | assertTrue(布尔条件) | 检查条件是否为真 | assertFalse(布尔条件) | 检查条件是否为假 |
|