作者:Chang K. Choe, Mark True
在测试驱动的开发过程中,JUnit 可能是一件宝贵的工具;或者在称作软件开发的正在进行中的危险期,它可能是另一件令人头痛之事的源泉。本文讨论了使用 JUnit、Cactus 和 Ant 创建 J2EE 测试装置的有效设计。它假定读者具备关于这些工具的基本知识,并了解测试 J2EE 应用程序的固有挑战。本文描述其某些原理时,不够精细详尽,因为代码语法会不可避免地变化,而且还因为,我们觉得理解所讲内容最好的方法是自己试用。如果您已经在其他测试装置上获得了有限的成功,而且不想在任何单个工具上做出巨大投入,那么本文对您不断增长的测试需要可能有所帮助。
测试装置应该包含什么?
我们觉得测试装置的作用是确保测试过程在每次运行中都平稳、可靠地运行,这样,您就可以集中在其他更重要的任务(即查找和修补错误)上。
在测试装置中,我们往往期待以下特性:
1. 支持迭代开发
2. 易于维护
3. 容易重复运行
4. 易于解释结果
5. 易于扩展
6. 易于调试
7. 易于自动操作
目前有发展趋势了吗?我们认为,测试装置应该将烦恼从运行测试和解释结果中剔除。它应该与构建环境完美地集成在一起,而且应该可用于开发及 QA 团队内每一个人。正是由于这些非常特别的原因,开放源代码工具已经成为了受青睐的选择。我们已经领略了一些最受青睐的开放源代码 Java 工具,并且已经提供了一份简要概述,关于如何通过应用一些简单设计模式和最佳实践来最好地理解它们。提供了一些例子,用以帮助理解如何能够应用这些设计,但是不应该将其看作达到目标的唯一方法。
动态构建测试套件
JUnit 和 Cactus 的其中一个难点是, 如何打包和执行测试套件。TestSuite 对象实现 Test 接口,TestCase 也使用它。这允许链接几个嵌套 TestSuites,而不必了解关于底层实现的任何细节。
TestSuite suite = new TestSuite();
suite.addTest(Kent.suite());
suite.addTest(Erich.suite());
|
在精心组织构建环境之后,这就可以工作了,在该环境中,同一测试套件在单一入口点被重复调用,以执行测试。然而,当需要对测试套件进行修改或者打算只运行单个 TestCase时,维护的难题就开始背离您最开始的动机了(我们讨厌发生这种情况)。这会要求从程序上改变方法调用和/或重新组织 TestSuite 类,所有这些都需要重新编译。如果正在调用 Cactus 测试,或者在适当的位置具备 Ant 脚本,随着越来越多的文件需要修改,问题就累积起来了。
单入口点有助于简化要调用哪个类,以及调整测试装置如何运行,但是它不应该静态地指示执行路径的其余部分。给定其正在运行的上下文,它应该能够改变自己的行为。否则,TestSuite 的行为就几乎成为本质上是声明性的,而没有了声明性编程的任何益处。
如果您喜欢声明性地定义测试套件,而不喜欢 JUnit 的 TestSuite 的强制性方面,建议使用 Builder 模式并编写一个TestSuiteBuilder,TestSuiteBuilder 综合了两者的优点。Builder 模式不同于 Factory 模式,因为它仅仅返回一个测试名集合,而不是具体的实现。以下是 TestSuiteBuilder 中的测试套件方法的外部特征的例子:
public static Test suite()
{
Properties registry = getRegistry(System.getProperty("registry.properties"));
TestSuite suite = getMatches(registry, modules);
return suite;
}
|
使用测试注册表
在先前的例子中,将一个属性文件用作了测试注册表。该测试注册表列出了所有使用完全合格的类名可用的测试。在属性文件中赋的值是分类或者模块,特殊的测试应该在其下加以分类。例如:
com.home.FirstTest = first cactus
com.later.AnotherTest = another time
com.again.UltimateTest = ultimate cactus
|
当汇编测试套件时,TestSuiteBuilder 将这些模块用作过滤器。如果只想运行分类为“first”的测试,那么, TestSuiteBuilder 就会返回 “com.home.FirstTest” ,而且只加载这个类。如果打算运行所有的“cactus”测试,那么,TestSuiteBuilder 就会返回包含“com.home.FirstTest” 和“com.again.UltimateTest” 的 TestSuite。
使用开放源代码工具
如果已经在使用 Cactus,那么,便知道其重定向对 J2EE 容器内部对象的请求的能力。为了便于加载测试类,建议将测试直接编译到 WEB-INF/classes目录下。这将有助于支持迭代开发,在迭代开发中,可以修改测试、重新编译以及重新部署,而不必重新启动服务器。 在与 Ant集成之后,就可以更有效地编写和运行了,因为 WebLogic 赋予了通过在 WEB-INF 中联系一个 REDEPLOY 文件而重新部署Web 应用程序的能力。
<touch file="/WEB-INF/REDEPLOY"/>
|
使用 Ant 的另一好处是其大量使用属性。早先提到的那些模块可能被Ant 的运行时获取,并作为属性文件中的一个命令行参数或一个入口传递给了 TestSuiteBuilder。
ant compile deploy run -Dmodule.name=first
|
您的运行目标看起来可能类似这样:
<junit>
<sysproperty key="cactus.contextURL" value="http://:/"/>
<sysproperty key="registry.properties" value=""/>
<sysproperty key="module.name" value=""/>
<test name="com.chameleon.TestSuiteBuilder" todir=""/>
<formatter type="xml"/>
</junit>
|
结束语
这些是期望帮您变得更加富有成效、并且允许在不切实际的最后期限之前交付 J2EE 应用程序的工具。若头脑中没有一些构思,谁也不会冒然设计自己的应用程序,那么,为什么您的测试装置就应该不同呢?使用 Builder 模式动态汇编测试套件,并依靠开放源代码工具,比如,Cactus 和 Ant ,会节省大量时间,免除大量跑腿的工作。往项目中融入一点自动化并不总意味着将会更易于维护。然而,应用设计模式至少会给您一个控制开发环境的开端。 |