按照约定,测试类的名称中包含我所测试的类的名称,但将 Test 附加到结尾。在本例中,我们的测试类是 HelloWorldTest.java 。我复制了 SkeletonTest 中的代码,并添加了 testSayHello() 来测试 sayHello() 。请注意 HelloWorldTest 扩展了 TestCase。JUnit 框架提供了 assert 和 assertEquals 方法,我们可以使用这些方法来进行验证。 HelloWorldTest.java 显示在清单 2 中。
清单 2. HelloWorldTest.java
package test.com.company; import com.company.HelloWorld; import junit.framework.TestCase; import junit.framework.AssertionFailedError; /** * JUnit 3.2 testcases for HelloWorld */ public class HelloWorldTest extends TestCase { public HelloWorldTest(String name) { super(name); } public static void main(String args[]) { junit.textui.TestRunner.run(HelloWorldTest.class); } public void testSayHello() { HelloWorld world = new HelloWorld(); assert( world!=null ); assertEquals("Hello World", world.sayHello() ); } }
testSayHello() 看上去和 HelloWorld.java 中原来的 main 方法类似,但有一个主要的不同之处。它不是执行 System.out.println 并显示结果,而是添加了一个 assertEquals() 方法。如果两个值不同, assertEquals 将打印出两个输入的值。您可能已经注意到这个方法不起作用!HelloWorld 中的 sayHello() 方法不返回字符串。如果我先写过测试,会捕捉到这一点。我将 "Hello World" 字符串与输出流联结起来。这样,按照清单 3 中显示的那样重写了 HelloWorld,去掉 main() ,并更改了 sayHello() 的返回类型。
清单 3. Hello world 测试案例。
package com.company; public class HelloWorld { public String sayHello() { return "Hello World"; } }
如果我保留了 main() 并修改了联系,代码看上去如下:
public static void main( String[] args ) { HelloWorld world = new HelloWorld(); System.out.println(world.sayHello()); }
新的 main() 与我测试程序中的 testSayHello() 非常相似。是的,它看上去不象是一个现实世界中的问题(这是人为示例的问题),但它说明了问题。在单独的应用程序中编写 main() 可以改进您的设计,同时帮助您设计测试。现在我们已经创建了一个测试类,让我们使用 Ant 来将它集成到构建中。
使用 Ant 将测试集成到构建中
Jakarta Project 将 Ant 工具说成“不带 make 缺点的 make”。Ant 正在成为开放源代码世界中实际上的标准。原因很简单:Ant 是使用 Java 语言编写的,这种语言可以让构建过程在多种平台上使用。这种特性简化了在不同 OS 平台之间的程序员的合作,而合作是开放源代码社区的一种需要。您可以在自己选择的平台上进行开发 和 构建。Ant 的特性包括:
类可扩展性 Java 类可用于扩展构建特性,而不必使用基于 shell 的命令。
开放源代码 因为 Ant 是开放源代码,因此类扩展示例很充足。我发现通过示例来学习非常棒。
XML 可配置 Ant 不仅是基于 Java 的,它还使用 XML 文件配置构建过程。假设构建实际上是分层的,那么使用 XML 描述 make 过程是其逻辑层。另外,如果您了解 XML,要学习如何配置构建更简单一些。
图 2 简要介绍了一个配置文件。配置文件由目标树构成。每个目标都包含了要执行的任务,其中任务是可以执行的代码。在本例中, mkdir 是目标 compile 的任务。 mkdir 是建立在 Ant 中的一个任务,用于创建目录。 Ant 带有一套健全的内置任务。您也可以通过扩展 Ant 任务类来添加自己的功能。
每个目标都有的名称和可选的相关性。目标相关性需要在执行目标任务列表之前执行。例如图 2 所示,在执行 compile 目标中的任务之前需要先运行 JUNIT 目标。这种类型的配置可以让您在一个配置中有多个树。
图 2. Ant XML 构建图
与经典 make 实用程序的相似性是非常显著的。这是理所当然的,因为 make 是 make。但也要记住有一些差异:通过 Java 实现的跨平台和可扩展性,通过 XML 实现的可配置,还有开放源代码。
下载和安装 Ant
首先下载 Ant(请参阅参考资料)。将 Ant 解压缩到 tools 目录,再将 Ant bin 目录添加到路径中。(在我的机器上是 e: oolsantin 。)设置 ANT_HOME 环境变量。在 NT 中,这意味着进入系统属性,然后以带有值的变量形式添加 ANT_HOME。ANT_HOME 应该设置为 Ant 根目录,即包含 bin 和 lib 目录的目录。(对我来说,是 e: oolsant 。)确保 JAVA_HOME 环境变量设置为安装了 JDK 的目录。Ant 文档有关于安装的详细信息。
下载和安装 JUnit
下载 JUnit 3.2(请参阅参考资料)。解开 junit.zip ,并将 junit.jar 添加到 CLASSPATH。如果将 junit.zip 解包到类路径中,可以通过运行以下命令来测试安装: java junit.textui.TestRunner junit.samples.AllTests
定义目录结构
在开始我们的构建和测试过程之前,需要一个项目布局。图 3 显示了我的样本项目的布局。下面描述了布局的目录结构:
build -- 类文件的临时构建位置。构建过程将创建这个目录。
src -- 源代码的位置。 Src 被分为 test 文件夹和 main 文件夹,前者用于所有的测试代码,而后者包含可交付的代码。将测试代码与主要代码分离提供了几点特性。首先,使主要代码中的混乱减少。其次,它允许包对齐。我热衷与将类和与其相关的包放置在一起。测试应该和测试在一起。它还有助于分发过程,因为你不可能打算将单元测试分发给客户。
在实际中,我们有多个目录,例如 distribution 和 documentation 。我们还会在 main 下有多个用于包的目录,例如 com.company.util 。
因为目录结构经常变动,所以在 build.xml 中有这些变动的全局字符串常数是很重要的。
图 3. 项目布局图
Ant 构建配置文件示例