目录:
Junit4 使用
Ant结合Junit4实现自动化测试
一、Junit4 使用介绍
JUnit 是 Java 社区中知名度最高的单元测试工具。它诞生于 1997 年,由 Erich Gamma 和 Kent Beck 共同开发完成。其中 Erich Gamma 是经典著作《设计模式:可复用面向对象软件的基础》一书的作者之一,并在 Eclipse 中有很大的贡献;Kent Beck 则是一位极限编程(XP)方面的专家和先驱。
麻雀虽小,五脏俱全。JUnit 设计的非常小巧,但是功能却非常强大。Martin Fowler 如此评价 JUnit:在软件开发领域,从来就没有如此少的代码起到了如此重要的作用。它大大简化了开发人员执行单元测试的难度,特别是 JUnit 4 使用 Java 5 中的注解(annotation)使测试变得更加简单。
在单元测试前首先规划单元测试代码应放在什么地方。把它和被测试代码混在一起,这显然会照成混乱,因为单元测试代码是不会出现在最终产品中的。建议分别为单元测试代码与被测试代码创建单独的目录,并保证测试代码和被测试代码使用相同的包名。这样既保证了代码的分离,同时还保证了查找的方便。
下面的例子来自开发实践:工具类 WordDealUtil 中的静态方法 wordFormat4DB 是专用于处理 Java 对象名称向数据库表名转换的方法(可以在代码注释中可以得到更多详细的内容)。下面是第一次编码完成后大致情形:
package org.wh.util; import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import org.junit.Test; public class WordDealUtil { public static String wordFormat4DB(String name){ Pattern p = Pattern.compile("[A-Z]"); Matcher m = p.matcher(name); StringBuffer sb = new StringBuffer(); while(m.find()){ m.appendReplacement(sb, "_"+m.group()); } return m.appendTail(sb).toString().toLowerCase(); } }
|
它是否能按照预期的效果执行呢?尝试为它编写 JUnit 单元测试代码如下:
package org.wh.util;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import org.junit.Test;
public class TestWordDealUtil { // 测试 wordFormat4DB 正常运行的情况 @Test public void wordFormat4DBNormal(){ String target = "employeeInfo"; String result = WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info", result); } } |
测试类 TestWordDealUtil 之所以使用“Test”开头,完全是为了更好的区分测试类与被测试类。测试方法 wordFormat4DBNormal 调用执行被测试方法 WordDealUtil.wordFormat4DB,以判断运行结果是否达到设计预期的效果。需要注意的是,测试方法 wordFormat4DBNormal 需要按照一定的规范书写:
1. 测试方法必须使用注解 org.junit.Test 修饰。
2. 测试方法必须使用public void修饰,而且不能带有任何参数。
测试方法中要处理的字符串为“employeeInfo”,按照设计目的,处理后的结果应该为“employee_info”。assertEquals 是由 JUnit 提供的一系列判断测试结果是否正确的静态断言方法(位于类 org.junit.Assert 中)之一,使用它将执行结果 result 和预期值“employee_info”进行比较,来判断测试是否成功。
下面简单介绍一下静态类org.junit.Assert。
该类主要包含以下22个方法:
1.assertEquals(),8个重载,用来查看对象中存的值是否是期待的值,与字符串比较中使用的equals()方法类似;
2.assertFalse()和assertTrue(),各2个重载,用来查看变量是是否为false或true,如果assertFalse()查看的变量的值是false则测试成功,如果是true则失败,assertTrue()与之相反;
3.assertSame()和assertNotSame(),各2个重载,用来比较两个对象的引用是否相等和不相等,类似于通过“==”和“!=”比较两个对象;
4.assertNull()和assertNotNull(),各2个重载,用来查看对象是否为空和不为空;
5.fail (),2个重载,意为失败,用来抛出AssertionError错误。有两个用途:首先是在测试驱动开发中,由于测试用例都是在被测试的类之前编写,而写成时又不清楚其正确与否,此时就可以使用fail方法抛出错误进行模拟;其次是抛出意外的错误,比如要测试的内容是从数据库中读取的数据是否正确,而导致错误的原因却是数据库连接失败。
单元测试的范围要全面,比如对边界值、正常值、错误值得测试;对代码可能出现的问题要全面预测,而这也正是需求分析、详细设计环节中要考虑的。显然,以上测试才刚刚开始,需继续补充一些对特殊情况的测试:
package org.wh.util;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import org.junit.Test;
public class TestWordDealUtil { // 测试 wordFormat4DB 正常运行的情况 @Test public void wordFormat4DBNormal(){ String target = "employeeInfo"; String result = WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info", result); }
// 测试 null 时的处理情况 @Test public void wordFormat4DBNull(){ String target = null; String result = WordDealUtil.wordFormat4DB(target);
assertNull(result); }
// 测试空字符串的处理情况 @Test public void wordFormat4DBEmpty(){ String target = ""; String result = WordDealUtil.wordFormat4DB(target);
assertEquals("", result); }
// 测试当首字母大写时的情况 @Test public void wordFormat4DBegin(){ String target = "EmployeeInfo"; String result = WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info", result); }
// 测试当尾字母为大写时的情况 @Test public void wordFormat4DBEnd(){ String target = "employeeInfoA"; String result = WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info_a", result); }
// 测试多个相连字母大写时的情况 @Test public void wordFormat4DBTogether(){ String target = "employeeAInfo"; String result = WordDealUtil.wordFormat4DB(target);
assertEquals("employee_a_info", result); } } |
再次运行测试。此时,JUnit提示有两个测试情况未通过测试——当首字母大写时得到的处理结果与预期的有偏差,造成测试失败(failure);而当测试对 null 的处理结果时,则直接抛出了异常——测试错误(error)。显然,被测试代码中并没有对首字母大写和 null 这两种特殊情况进行处理,修改如下:
//修改后的方法wordFormat4DB
public static String wordFormat4DB(String name){
if(name == null){
return null;
}
Pattern p = Pattern.compile("[A-Z]");
Matcher m = p.matcher(name);
StringBuffer sb = new StringBuffer();
while(m.find()){
if(m.start() != 0)
m.appendReplacement(sb, ("_"+m.group()).toLowerCase());
}
return m.appendTail(sb).toString().toLowerCase();
}
JUnit 将测试失败的情况分为两种:failure 和 error。Failure 一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;而 error 则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误(测试代码也是代码,同样无法保证完全没有缺陷),也可能是被测试代码中的一个隐藏的bug。
再次运行测试。通过对 WordDealUtil.wordFormat4DB 比较全面的单元测试,现在的代码已经比较稳定,可以作为 API 的一部分提供给其它模块使用了。
当然,JUnit 提供的功能决不仅仅如此简单,在接下来的内容中,会看到 JUnit 中很多有用的特性,掌握它们对灵活的编写单元测试代码非常有帮助。
Fixture
何谓 Fixture?它是指在执行一个或者多个测试方法时需要的一系列公共资源或者数据,例如测试环境,测试数据等等。JUnit 专门提供了设置公共 Fixture 的方法,同一测试类中的所有测试方法都可以共用它来初始化 Fixture 和注销 Fixture。和编写 JUnit 测试方法一样,公共 Fixture 的设置也很简单,只需要:
1. 使用注解 org.junit.Before修饰用于初始化 Fixture 的方法。
2. 使用注解 org.junit.After修饰用于注销 Fixture 的方法。
3. 保证这两种方法都使用public void修饰,而且不能带有任何参数。
遵循上面的三条原则,编写出的代码大体是这个样子:
//初始化Fixture方法
@Before
public void init(){……}
//注销Fixture方法
@After
public void destroy(){……}
这样,在每一个测试方法执行之前,JUnit 会保证 init 方法已经提前初始化测试环境,而当此测试方法执行完毕之后,JUnit 又会调用 destroy 方法注销测试环境。注意是每一个测试方法的执行都会触发对公共 Fixture 的设置,也就是说使用注解 Before 或者 After 修饰的公共 Fixture 设置方法是方法级别的(图1)。这样便可以保证各个独立的测试之间互不干扰,以免其它测试代码修改测试环境或者测试数据影响到其它测试代码的准确性。
图1 方法级别 Fixture 执行示意图
可是,这种 Fixture 设置方式还是引来了批评,因为它效率低下,特别是在设置 Fixture 非常耗时的情况下(例如设置数据库链接)。而且对于不会发生变化的测试环境或者测试数据来说,是不会影响到测试方法的执行结果的,也就没有必要针对每一个测试方法重新设置一次 Fixture。因此在 JUnit 4 中引入了类级别的 Fixture 设置方法,编写规范如下:
1. 使用注解org.junit.BeforeClass修饰用于初始化Fixture 的方法。
2. 使用注解 org.junit.AfterClass 修饰用于注销 Fixture 的方法。
3. 保证这两种方法都使用 public static void 修饰,而且不能带有任何参数。
类级别的 Fixture 仅会在测试类中所有测试方法执行之前执行初始化,并在全部测试方法测试完毕之后执行注销方法(图6)。代码范本如下:
//类级别Fixture初始化方法
@BeforeClass
public static void dbInit(){……}
//类级别Fixture注销方法
@AfterClass
public static void dbClose(){……}
图2 类级别 Fixture 执行示意图
运行以下例子,可以更深刻理解方法的执行顺序:
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class Example {
@BeforeClass
public static void init(){
System.out.println("public static void init ...");
}
@BeforeClass
public static void init1(){
System.out.println("public static void init1 ...");
}
@AfterClass
public static void release(){
System.out.println("public static release ...");
}
@Before
public void before(){
System.out.println("before ...");
}
@Before
public void before1(){
System.out.println("before1 ...");
}
@Test
public void example() {
System.out.println("---------Test Begin--------------");
System.out.println("Hello...");
}
@After
public void close1() {
System.out.println("After,should close 1...");
}
@Test
public void example1() {
System.out.println("---------Test Begin--------------");
System.out.println("Hello 1...");
}
@After
public void close() {
System.out.println("After,should close...");
}
@Test
public void example2() {
System.out.println("---------Test Begin--------------");
System.out.println("Hello 2...");
}
@After
public void close2() {
System.out.println("After,should close 2...");
}
@Ignore("Not retry yet")
public void testIndexOut() {
System.out.println("Exception test...");
}
public Example() {
System.out.println("Example construct running...");
}
public static void main(String[] args) {
JUnitCore().main(new String[] { “Example” });
}
}
异常以及时间测试
注解org.junit.Test 中有两个非常有用的参数:expected和timeout。参数 expected代表测试方法期望抛出指定的异常,如果运行测试并没有抛出这个异常,则JUnit 会认为这个测试没有通过。这为验证被测试方法在错误的情况下是否会抛出预定的异常提供了便利。举例来说,方法supportDBChecker用于检查用户使用的数据库版本是否在系统的支持的范围之内,如果用户使用了不被支持的数据库版本,则会抛出运行时异常UnsupportedDBVersionException。测试方法 supportDBChecker在数据库版本不支持时是否会抛出指定异常的单元测试方法大体如下:
@Test(expected=UnsupportedDBVersionException.class)
public void unsupportedDBCheck(){
……
}
注解org.junit.Test的另一个参数timeout,指定被测试方法被允许运行的最长时间应该是多少,如果测试方法运行时间超过了指定的毫秒数,则JUnit认为测试失败。这个参数对于性能测试有一定的帮助。例如,如果解析一份自定义的XML文档花费了多于1秒的时间,就需要重新考虑XML结构的设计,那单元测试方法可以这样来写:
@Test(timeout=1000)
public void selfXMLReader(){
……
}
忽略测试方法
JUnit提供注解org.junit.Ignore用于暂时忽略某个测试方法,因为有时候由于测试环境受限,并不能保证每一个测试方法都能正确运行。例如下面的代码便表示由于没有了数据库链接,提示JUnit忽略测试方法 unsupportedDBCheck:
@ Ignore(“db is down”)
@Test(expected=UnsupportedDBVersionException.class)
public void unsupportedDBCheck(){
……
}
但是一定要小心。注解org.junit.Ignore只能用于暂时的忽略测试,如果需要永远忽略这些测试,一定要确认被测试代码不再需要这些测试方法,以免忽略必要的测试点。
测试运行器
测试运行器是又一个新概念,JUnit中所有的测试方法都是由它负责执行的。JUnit为单元测试提供了默认的测试运行器,但JUnit 并没有限制必须使用默认的运行器。相反,不仅可以定制自己的运行器(所有的运行器都继承自org.junit.runner.Runner),而且还可以为每一个测试类指定使用某个具体的运行器。指定方法也很简单,使用注解org.junit.runner.RunWith在测试类上显式的声明要使用的运行器即可:
@RunWith(CustomTestRunner.class)
public class TestWordDealUtil {
……
}
显而易见,如果测试类没有显式的声明使用哪一个测试运行器,JUnit会启动默认的测试运行器执行测试类(比如上面提及的单元测试代码)。一般情况下,默认测试运行器可以应对绝大多数的单元测试要求;当使用JUnit提供的一些高级特性(例如即将介绍的两个特性)或者针对特殊需求定制JUnit测试方式时,显式的声明测试运行器就必不可少了。
测试套件
在实际项目中,随着项目进度的开展,单元测试类会越来越多,可是直到现在还只会一个一个的单独运行测试类,这在实际项目实践中肯定是不可行的。为了解决这个问题,JUnit 提供了一种批量运行测试类的方法,叫做测试套件。这样,每次需要验证系统功能正确性时,只执行一个或几个测试套件便可以了。测试套件的写法非常简单,只需要遵循以下规则:
1. 创建一个空类作为测试套件的入口。
2. 使用注解org.junit.runner.RunWith和org.junit.runners.Suite. SuiteClasses修饰这个空类。
3. 将org.junit.runners.Suite作为参数传入注解RunWith,以提示 JUnit为此类使用套件运行器执行。
4. 将需要放入此测试套件的测试类组成数组作为注解 SuiteClasses的参数。
5. 保证这个空类使用public修饰,而且存在公开的不带有任何参数的构造函数。
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runner.JUnitCore;
……
@RunWith(Suite.class)
@Suite.SuiteClasses({TestWordDealUtil.class,...})
public class RunAllUtilTestsSuite {
public static void main(String[] args) {
JUnitCore().main(new String[] { “RunAllUtilTestsSuite” });
}
}
上例代码中,将前文提到的测试类 TestWordDealUtil 放入了测试套件 RunAllUtilTestsSuite 中,运行测试套件,可以看到测试类 TestWordDealUtil被调用执行了。测试套件中不仅可以包含基本的测试类,而且可以包含其它的测试套件,这样可以很方便的分层管理不同模块的单元测试代码。但是,一定要保证测试套件之间没有循环包含关系,否则无尽的循环就会出现在面前……。
二、ANT与Junit4结合完成自动构建
1、借助Eclipse创建build.xml文件
选中工程--点击右键--点击Export选项,弹出如下对话框
创建的build文件如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- WARNING: Eclipse auto-generated file. Any modifications will be overwritten. To include a user specific buildfile here, simply create one in the same directory with the processing instruction <?eclipse.ant.import?> as the first entry and export the buildfile again. --> <project basedir="." default="build" name="firstWeb"> <property environment="env"/> <property name="ECLIPSE_HOME" value="../../eclipse3.6"/> <property name="junit.output.dir" value="junit"/> <property name="debuglevel" value="source,lines,vars"/> <property name="target" value="1.6"/> <property name="source" value="1.6"/> <path id="Apache Tomcat v6.0 [Apache Tomcat v6.0 (2)].libraryclasspath"> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/annotations-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina-ant.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina-ha.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina-tribes.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/ecj-4.2.2.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/el-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/jasper-el.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/jasper.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/jsp-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/servlet-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-coyote.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-dbcp.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-i18n-es.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-i18n-fr.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-i18n-ja.jar"/> </path> <path id="EAR Libraries.libraryclasspath"/> <path id="Web App Libraries.libraryclasspath"/> <path id="JUnit 4.libraryclasspath"> <pathelement location="${ECLIPSE_HOME}/plugins/org.junit4_4.3.1/junit.jar"/> </path> <path id="firstWeb.classpath"> <pathelement location="build/classes"/> <path refid="Apache Tomcat v6.0 [Apache Tomcat v6.0 (2)].libraryclasspath"/> <path refid="EAR Libraries.libraryclasspath"/> <path refid="Web App Libraries.libraryclasspath"/> <path refid="JUnit 4.libraryclasspath"/> </path> <target name="init"> <mkdir dir="build/classes"/> <copy includeemptydirs="false" todir="build/classes"> <fileset dir="src" excludes="**/*.launch, **/*.java"/> </copy> <copy includeemptydirs="false" todir="build/classes"> <fileset dir="test" excludes="**/*.launch, **/*.java"/> </copy> </target> <target name="clean"> <delete dir="build/classes"/> </target> <target depends="clean" name="cleanall"/> <target depends="build-subprojects,build-project" name="build"/> <target name="build-subprojects"/> <target depends="init" name="build-project"> <echo message="${ant.project.name}: ${ant.file}"/> <javac debug="true" debuglevel="${debuglevel}" destdir="build/classes" source="${source}" target="${target}"> <src path="src"/> <classpath refid="firstWeb.classpath"/> </javac> <javac debug="true" debuglevel="${debuglevel}" destdir="build/classes" source="${source}" target="${target}"> <src path="test"/> <classpath refid="firstWeb.classpath"/> </javac> </target> <target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects"/> <target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler"> <copy todir="${ant.library.dir}"> <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/> </copy> <unzip dest="${ant.library.dir}"> <patternset includes="jdtCompilerAdapter.jar"/> <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/> </unzip> </target> <target description="compile project with Eclipse compiler" name="build-eclipse-compiler"> <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/> <antcall target="build"/> </target> <target name="AllTests1"> <mkdir dir="${junit.output.dir}"/> <junit fork="yes" printsummary="withOutAndErr"> <formatter type="xml"/> <test name="org.wh.util.AllTests1" todir="${junit.output.dir}"/> <classpath refid="firstWeb.classpath"/> </junit> </target> <target name="TestWordDealUtil"> <mkdir dir="${junit.output.dir}"/> <junit fork="yes" printsummary="withOutAndErr"> <formatter type="xml"/> <test name="org.wh.util.TestWordDealUtil" todir="${junit.output.dir}"/> <classpath refid="firstWeb.classpath"/> </junit> </target> <target name="TestWordDealUtil1"> <mkdir dir="${junit.output.dir}"/> <junit fork="yes" printsummary="withOutAndErr"> <formatter type="xml"/> <test name="org.wh.util.TestWordDealUtil1" todir="${junit.output.dir}"/> <classpath refid="firstWeb.classpath"/> </junit> </target> <target name="TestWordDealUtilWithParam"> <mkdir dir="${junit.output.dir}"/> <junit fork="yes" printsummary="withOutAndErr"> <formatter type="xml"/> <test name="org.wh.util.TestWordDealUtilWithParam" todir="${junit.output.dir}"/> <classpath refid="firstWeb.classpath"/> </junit> </target> <target name="test (1)"> <mkdir dir="${junit.output.dir}"/> <junit fork="yes" printsummary="withOutAndErr"> <formatter type="xml"/> <classpath refid="firstWeb.classpath"/> </junit> </target> <target name="RunAllUtilTestsSuite"> <mkdir dir="${junit.output.dir}"/> <junit fork="yes" printsummary="withOutAndErr"> <formatter type="xml"/> <test name="org.wh.util.RunAllUtilTestsSuite" todir="${junit.output.dir}"/> <classpath refid="firstWeb.classpath"/> </junit> </target> <target name="junitreport"> <junitreport todir="${junit.output.dir}"> <fileset dir="${junit.output.dir}"> <include name="TEST-*.xml"/> </fileset> <report format="frames" todir="${junit.output.dir}"/> </junitreport> </target> </project>
|
2、修改build.xml文件
创建完成后,默认执行”build” target。执行junit测试套并生成测试报告的话需要修改该build.xml文件
1)默认执行target修改为:targer junitreport
<project basedir="." default="junitreport" name="firstWeb">
2)配置target的执行顺序(依赖关系)
一般的执行顺序
Clean-->build-->junit--->junitreport.
从新build前执行clean任务,删除class文件。
<target depends="clean,build-subprojects,build-project" name="build"/>
设置依赖关系运行测试套前需要进行build任务。
<target name="RunAllUtilTestsSuite" depends="build" >
生成junitreport前需要执行junit测试套/测试用例
<target name="junitreport" depends="RunAllUtilTestsSuite">
修改后的build文件如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- WARNING: Eclipse auto-generated file. Any modifications will be overwritten. To include a user specific buildfile here, simply create one in the same directory with the processing instruction <?eclipse.ant.import?> as the first entry and export the buildfile again. --> <project basedir="." default="junitreport" name="firstWeb"> <property environment="env"/> <property name="ECLIPSE_HOME" value="../../eclipse3.6"/> <property name="junit.output.dir" value="junit"/> <property name="debuglevel" value="source,lines,vars"/> <property name="target" value="1.6"/> <property name="source" value="1.6"/> <path id="Apache Tomcat v6.0 [Apache Tomcat v6.0 (2)].libraryclasspath"> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/annotations-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina-ant.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina-ha.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina-tribes.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/catalina.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/ecj-4.2.2.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/el-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/jasper-el.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/jasper.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/jsp-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/servlet-api.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-coyote.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-dbcp.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-i18n-es.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-i18n-fr.jar"/> <pathelement location="C:/Program Files (x86)/Apache Software Foundation/Tomcat 6.0/lib/tomcat-i18n-ja.jar"/> </path> <path id="EAR Libraries.libraryclasspath"/> <path id="Web App Libraries.libraryclasspath"/> <path id="JUnit 4.libraryclasspath"> <pathelement location="${ECLIPSE_HOME}/plugins/org.junit4_4.3.1/junit.jar"/> </path> <path id="firstWeb.classpath"> <pathelement location="build/classes"/> <path refid="Apache Tomcat v6.0 [Apache Tomcat v6.0 (2)].libraryclasspath"/> <path refid="EAR Libraries.libraryclasspath"/> <path refid="Web App Libraries.libraryclasspath"/> <path refid="JUnit 4.libraryclasspath"/> </path> <target name="init"> <mkdir dir="build/classes"/> <copy includeemptydirs="false" todir="build/classes"> <fileset dir="src" excludes="**/*.launch, **/*.java"/> </copy> <copy includeemptydirs="false" todir="build/classes"> <fileset dir="test" excludes="**/*.launch, **/*.java"/> </copy> </target> <target name="clean"> <delete dir="build/classes"/> </target> <target depends="clean" name="cleanall"/> <target depends="clean,build-subprojects,build-project" name="build"/> <target name="build-subprojects"/> <target depends="init" name="build-project"> <echo message="${ant.project.name}: ${ant.file}"/> <javac debug="true" debuglevel="${debuglevel}" destdir="build/classes" source="${source}" target="${target}"> <src path="src"/> <classpath refid="firstWeb.classpath"/> </javac> <javac debug="true" debuglevel="${debuglevel}" destdir="build/classes" source="${source}" target="${target}"> <src path="test"/> <classpath refid="firstWeb.classpath"/> </javac> </target> <target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects"/> <target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler"> <copy todir="${ant.library.dir}"> <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/> </copy> <unzip dest="${ant.library.dir}"> <patternset includes="jdtCompilerAdapter.jar"/> <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/> </unzip> </target> <target description="compile project with Eclipse compiler" name="build-eclipse-compiler"> <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/> <antcall target="build"/> </target>
<target name="RunAllUtilTestsSuite" depends="build"> <mkdir dir="${junit.output.dir}"/> <junit fork="yes" printsummary="withOutAndErr"> <formatter type="xml"/> <test name="org.wh.util.RunAllUtilTestsSuite" todir="${junit.output.dir}"/> <classpath refid="firstWeb.classpath"/> </junit> </target> <target name="junitreport" depends="RunAllUtilTestsSuite"> <junitreport todir="${junit.output.dir}"> <fileset dir="${junit.output.dir}"> <include name="TEST-*.xml"/> </fileset> <report format="frames" todir="${junit.output.dir}"/> </junitreport> </target> </project>
|
3、用Ant完成程序构建并运行测试套
运行bulid.xml文件后得到的结果如下:
4、查看测试报告:用IE打开工程目录下的junit\index.html文件可以看到单元测试套执行结果。