测试开发

《JUnit实战》第9章 从 Ant中运行JUnit 测试(续1)

9.4 Ant的目标、项目、属性以及任务

当你构建一个软件项目时,你想要生成的常常不仅仅是二进制码。作为一个发布包,你可能也想生成 Javadoc。对于一个内部的开发构建,你可以跳过 Javadoc的生成。有时候,你可能会想要从头开始运行一个构建。你也可能只想编译那些修改过的类。为了帮助你管理这个构建过程,一个构建文件可以包含多个目标,封装了创建应用程序和相关资源所需要的不同任务。

为了使构建文件更易于配置和重用,Ant 允许你定义属性元素(类似于编程中的常量,或者Java中的final field)。核心的Ant概念如下所示:

构建文件( build file)——每个构建文件通常都与一个特定的开发项目有关。Ant使用project的 XML标签作为构建文件中的根元素来定义这个项目。它也允许你指定一个默认的目标,所以你就能够运行Ant而不带任何参数。

目标( target)——当你运行Ant时,你可以指定一个或多个目标来执行目标可以随意地申明它们依赖于其他的目标。如果你要求Ant 运行一个目标,Ant将优先执行它所依赖的目标。这就允许你创建一个依赖于其他目标的目标,例如,创建一个 distribution目标,而它依赖于其他的目标,如clean,compile,javadoc和 war。

属性元素(property element)——因为在一个项目内的许多目标都具有相同的设置,Ant允许你在整个构建文件内创建property元素来封装特定的设置并重用它们。要引用构建文件中的一个属性,你可以使用$(property)符号。如果要引用名为target.dir的属性,则可以写成${target.dir).

正如我们在上文中提到的,与其说Ant是一个工具,还不如说它是一个用来运行工具的框架。你可以使用property元素来设置一个工具所需要的参数和运行该工具的一个任务。虽然大量的任务已被Ant捆绑,但是你也可以编写你自己自定义的任务。想了解关于使用Ant进行开发的更多内容,我们建议读者可以参考《Ant in Action'》一书和访问Ant的官方站点。

代码9.1显示了第3章中的示例项目的构建文件的开头部分。构建文件的这一部分代码设置了默认的目标以及你的目标和任务将要使用的各种属性。

image.png

这段代码的开头指定了项目的名称为example,并设定了默认的目标以便测试。test 目标会出现在代码9.3 中。

接下来,我们包含了build.properties文件。因为开发人员可以将JAR文件保存在不同的位置,所以使用一个build.properties文件来定义它们的位置是一个很好的做法。许多开源的项目提供了一个示例build.properties文件,你可以复制和编辑这个文件以便适应你的环境。

我们使用 Ant 的 property任务来定义产品的目录和测试源代码的目录,以及编译产品和测试代码的不同目录的位置。为源代码和编译代码在不同的位置中定义源代码目录和测试代码目录,这不失为一个很好的做法。在以上示例中,我们以4个属性定义作为结尾。将编译产品代码和测试代码分开来,使得构建其他的工件(如JAR文件)更加容易,因为所有的编译产品代码都位于它自己的目录中。

Ant属性的一个重要方面是它们是不可变的。一旦你设定了一个属性值,你就不能再修改它了。如果你试图使用另一个property元素重新定义这个属性值,那么Ant就会忽略这个请求。

9.4.1 javac任务

对于简单的项目而言,从命令行中运行 javac编译器是非常简单的。但是,对带有多个包和源代码目录的产品来说,javac 编译器的配置会变得更加复杂。Ant的javac任务允许一个构建文件调用编译器,所以你就不再需要依赖于命令行。Ant 几乎为所有与构建相关的工作提供了一个任务,你就不必再在命令行上进行操作,包括对仓库(如CVS)的处理。你也可以找到Ant本身还没有定义的任务来处理任何事情。我们提到了CVS,但是如果你正在使用Subversion进行版本控制,那么你就可以在Subclipse项目之外使用SvnAnt。

一种标准的做法是,在你的构建文件中创建compile目标来调用Ant的javac任务,从而来编译产品和源代码。javac任务允许你设置所有的编译器选项,如源代码目录和目标目录、通过任务属性等。

代码9.2显示了调用Java编译器的产品和测试编译目标。

image.png

首先,我们声明了compile.java目标,来确保目标目录存在,并编译了产品源代码。Ant在构建文件顶部(如代码9.1所示)设置了属性target.classes.java.dir,并将它插人到starget.classes.java.dir}位置中。mkdir任务创建了一个目录,但是如果这个目录已经存在的话,那么、Ant 不会有任何提示。然后,这个构建使用javac调用了Java编译器,并传给它目标目录和源代码目录。

compile.test目标依赖于使用depends属性指定的compile.java目标(depends=compile.java")。当你调用compile.test目标时,如果 Ant还没有调用compile.java目标,那么它就会立即这么做。

你可能已经注意到,你并没有明确地把 JUnit的JAR添加到类路径中。记住,当你安装 Ant的时候,为了便于使用Ant的junit任务,你已经把JUnit的JAR文件复制到了${ANT_HOME}/lib目录中。因为junit.jar已经在你的类路径中,所以你不需要在javac任务中指定它来编译你的测试。

你需要添加一个嵌套的classpath元素⑥,以便把你刚刚编译了的产品类添加到类路径中,这是因为测试类调用了产品类。

最后,我们有一个compile目标⑦,它依赖于compile. java和 compile.test目标。

9.4.2 JUnit任务

在第3章中,我们已经手动运行了Defaultcontroller测试。为了对所做的修改进行测试,我们不得不执行以下操作:

编译源代码;

针对已编译的类,运行TestDefaultController测试用例。

我们可以让Ant来执行以上作为同一 build目标的一部分的两个步骤。代码9.3显示了test目标的详细代码。

image.png

我们声明了test目标,并定义它依赖于compile目标。如果我们要求Ant运行test目标,那么它将会在运行test目标之前先运行compile目标(除非Ant已经调用了compile)。在这个目标中定义的唯一任务是调用junit。junit 的printsummary属性会使得任务在测试的最后输出一个单行的摘要。将fork 设置为yes可以强制Ant为每个测试分别使用一个独立的Java 虚拟机(JVM)。虽然这会对性能产生负面的影响,但如果你为测试用例之间的相互干扰感到烦恼,这就是一个很好的解决办法。haltonfailure和haltonerror属性表明如果任何测试返回一个错误或者一个失败,就停止构建。在Ant中,错误是指意料之外的错误,类似于异常,而失败是指失败的断言调用。我们配置junit任务的格式程序来使用纯文本格式,并将测试结果输出到控制台。test的name属性定义了将要运行的测试的类名称。最后,我们为了这一个任务在类路径中添加我们刚刚编译的产品类和测试类。

这样就完成了我们的第一个test目标,接下来,我们要运行这个Ant构建。

相关内容

文章评论

表情

共 0 条评论,查看全部
  • 这篇文章还没有收到评论,赶紧来抢沙发吧~