??xml version="1.0" encoding="utf-8" standalone="yes"?>最新中文字幕一区二区三区,91久久线看在观草草青青,九色视频成人自拍http://www.aygfsteel.com/justuszhang2009/category/48859.htmlzh-cnFri, 24 Jun 2011 21:59:58 GMTFri, 24 Jun 2011 21:59:58 GMT60【{】单元测试利?JUnit 4http://www.aygfsteel.com/justuszhang2009/archive/2011/06/24/352430.html张益?/dc:creator>张益?/author>Fri, 24 Jun 2011 05:06:00 GMThttp://www.aygfsteel.com/justuszhang2009/archive/2011/06/24/352430.htmlhttp://www.aygfsteel.com/justuszhang2009/comments/352430.htmlhttp://www.aygfsteel.com/justuszhang2009/archive/2011/06/24/352430.html#Feedback0http://www.aygfsteel.com/justuszhang2009/comments/commentRss/352430.htmlhttp://www.aygfsteel.com/justuszhang2009/services/trackbacks/352430.html引言

毋庸|疑Q程序员要对自己~写的代码负责,(zhn)不仅要保证它能通过~译Q正常地q行Q而且要满需求和设计预期的效果。单元测试正是验证代码行为是否满预期的有效手段之一。但不可否认Q做试是g很枯燥无的事情Q而一遍又一遍的试则更是让人生畏的工作。幸q的是,单元试工具 JUnit 使这一切变得简单艺术v来?/p>

JUnit ?Java C֌中知名度最高的单元试工具。它诞生?1997 q_(d)?Erich Gamma ?Kent Beck 共同开发完成。其?Erich Gamma 是经典著作《设计模式:(x)可复用面向对象Y件的基础》一书的作者之一Qƈ?Eclipse 中有很大的A(ch)献;Kent Beck 则是一位极限编E(XPQ方面的专家和先驱?/p>

麻雀虽小Q五脏俱全。JUnit 设计的非常小巧,但是功能却非常强大。Martin Fowler 如此评h(hun) JUnitQ在软g开发领域,从来没有如此少的代码vC(jin)如此重要的作用。它大大化了(jin)开发h员执行单元测试的隑ֺQ特别是 JUnit 4 使用 Java 5 中的注解QannotationQɋ试变得更加单?/p>


JUnit 4 初体?/span>

在开始体?JUnit 4 之前Q我们需要以下Y件的支持Q?/p>

  • EclipseQ最为流行的 IDEQ它全面集成?JUnitQƈ从版?3.2 开始支?JUnit 4。当?JUnit q不依赖于Q?IDE。?zhn)可以?http://www.eclipse.org/ 上下载最新的 Eclipse 版本?/li>
  • AntQ基?Java 的开源构建工P(zhn)可以在 http://ant.apache.org/ 上得到最新的版本和丰富的文档。Eclipse 中已l集成了(jin) AntQ但是在撰写本文ӞEclipse 使用?Ant 版本较低Q必需 1.7 或者以上版本)(j)Q不能很好的支持 JUnit 4?/li>
  • JUnitQ它的官方网站是 http://www.junit.org/。?zhn)可以从上面获取关?JUnit 的最新消息。如果?zhn)和本文一样在 Eclipse 中?JUnitQ就不必再下载了(jin)?

首先为我们的体验新徏一?Java 工程 —— coolJUnit。现在需要做的是Q打开目 coolJUnit 的属性页 -> 选择“Java Build Path”子选项 -> 炚w?#8220;Add Library …”按钮 -> 在弹出的“Add Library”对话框中选择 JUnitQ?a >?1Q,q在下一中选择版本 4.1 后点?#8220;Finish”按钮。这样便?JUnit 引入到当前项目库中了(jin)?/p>
?1 为项目添?JUnit ?/strong>
?1 为项目添?JUnit ? src=

h?JDK 的版?/h2>

JUnit 4.1 是基?Java 5 的升U版本,它用了(jin) Tiger 中的很多新特性来化原有的使用方式。正因ؓ(f)如此Q它q不能直接运行在 JDK1.4.x 版本上。如果?zhn)需要在 JDK1.4.x 版本使用 JUnit 的话Q请使用 3.8.1 版本?/p>

可以开始编写单元测试了(jin)吗?{等……Q?zhn)打算把单元测试代码放在什么地方呢Q把它和被测试代码؜在一Pq显然会(x)照成混ؕQ因为单元测试代码是不会(x)出现在最l品中的。徏议?zhn)分别为单元测试代码与被测试代码创建单独的目录Qƈ保证试代码和被试代码使用相同的包名。这h保证?jin)代码的分离Q同时还保证?jin)查扄方便。遵照这条原则,我们在项?coolJUnit 根目录下d一个新目录 testsrcQƈ把它加入到项目源代码目录中(加入方式??2Q?/p>
?2 修改目源代码目?/strong>
?2 修改目源代码目? src=

现在我们得到?jin)一?JUnit 的最?jng)_践:(x)单元试代码和被试代码使用一L(fng)包,不同的目录?/p>

一切准备就l,一起开始体验如何?JUnit q行单元试吧。下面的例子来自W者的开发实践:(x)工具c?WordDealUtil 中的?rn)态方?wordFormat4DB 是专用于处理 Java 对象名称向数据库表名转换的方法((zhn)可以在代码注释中可以得到更多详l的内容Q。下面是W一ơ编码完成后大致情ŞQ?/p>
 package com.ai92.cooljunit; 

 import java.util.regex.Matcher; 
 import java.util.regex.Pattern; 

 /** 
 * 对名U、地址{字W串格式的内容进行格式检?
 * 或者格式化的工L(fng)
 * 
 * @author Ai92 
 */ 
 public class WordDealUtil { 

	 /** 
	 * ?Java 对象名称Q每个单词的头字母大写)(j)按照
	 * 数据库命名的?fn)惯q行格式?
	 * 格式化后的数据ؓ(f)写字母Qƈ且用下划线分割命名单词
	 * 
	 * 例如QemployeeInfo l过格式化之后变?employee_info 
	 * 
	 * @param name 	 Java 对象名称
	 */ 
	 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(); 
	 } 
 } 

它是否能按照预期的效果执行呢Q尝试ؓ(f)它编?JUnit 单元试代码如下Q?/p>
 package com.ai92.cooljunit; 

 import static org.junit.Assert.assertEquals; 
 import org.junit.Test; 

 public class TestWordDealUtil { 
	 // 试 wordFormat4DB 正常q行的情?
	 @Test public void wordFormat4DBNormal(){ 
		 String target = "employeeInfo"; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertEquals("employee_info", result); 
	 } 
 } 

很普通的一个类嘛!试c?TestWordDealUtil 之所以?#8220;Test”开_(d)完全是ؓ(f)?jin)更好的区分试cM被测试类。测试方?wordFormat4DBNormal 调用执行被测试方?WordDealUtil.wordFormat4DBQ以判断q行l果是否辑ֈ设计预期的效果。需要注意的是,试Ҏ(gu) wordFormat4DBNormal 需要按照一定的规范书写Q?/p>

  1. 试Ҏ(gu)必须使用注解 org.junit.Test 修饰?/li>
  2. 试Ҏ(gu)必须使用 public void 修饰Q而且不能带有M参数?

试Ҏ(gu)中要处理的字W串?#8220;employeeInfo”Q按照设计目的,处理后的l果应该?#8220;employee_info”。assertEquals 是由 JUnit 提供的一pd判断试l果是否正确的静(rn)态断aҎ(gu)Q位于类 org.junit.Assert 中)(j)之一Q我们用它?yu)执行结?result 和预期?#8220;employee_info”q行比较Q来判断试是否成功?/p>

看看q行l果如何。在试cM点击右键Q在弹出菜单中选择 Run As JUnit Test。运行结果如 下图所C:(x)


?3 JUnit q行成功界面
?3 JUnit q行成功界面

l色的进度条提示我们Q测试运行通过?jin)。但现在宣布代码通过?jin)单元测试还为时q早。记住:(x)(zhn)的单元试代码不是用来证明(zhn)是对的Q而是Z(jin)证明(zhn)没有错。因此单元测试的范围要全面,比如对边界倹{正常倹{错误值得试Q对代码可能出现的问题要全面预测Q而这也正是需求分析、详l设计环节中要考虑的。显?dng)我们的测试才刚刚开始,l箋补充一些对Ҏ(gu)情况的测试:(x)

 public class TestWordDealUtil { 
	……
	 // 试 null 时的处理情况
	 @Test public void wordFormat4DBNull(){ 
		 String target = null; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertNull(result); 
	 } 
	
	 // 试I字W串的处理情?
	 @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); 
	 } 
 } 

再次q行试。很遗憾QJUnit q行界面提示我们有两个测试情冉|通过试Q?a >?4Q?#8212;—当首字母大写时得到的处理l果与预期的有偏差,造成试p|QfailureQ;而当试?null 的处理结果时Q则直接抛出?jin)异?#8212;—试错误QerrorQ。显?dng)被测试代码中q没有对首字母大写和 null q两U特D情况进行处理,修改如下Q?/p>
 // 修改后的Ҏ(gu) wordFormat4DB 
 /** 
	 * ?Java 对象名称Q每个单词的头字母大写)(j)按照
	 * 数据库命名的?fn)惯q行格式?
	 * 格式化后的数据ؓ(f)写字母Qƈ且用下划线分割命名单词
	 * 如果参数 name ?nullQ则q回 null 
	 * 
	 * 例如QemployeeInfo l过格式化之后变?employee_info 
	 * 
	 * @param name Java 对象名称
	 */ 
	 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(); 
	 } 


?4 JUnit q行p|界面
?4 JUnit q行p|界面

JUnit 测试失败的情况分ؓ(f)两种Qfailure ?error。Failure 一般由单元试使用的断aҎ(gu)判断p|引vQ它表示在测试点发现?jin)问题;?error 则是׃码异常引Pq是试目的之外的发玎ͼ它可能生于试代码本n的错误(试代码也是代码Q同h法保证完全没有缺P(j)Q也可能是被试代码中的一个隐藏的 bug?/p>

L(fng)讎ͼ

L(fng)记这一?JUnit 最?jng)_践:(x)试M可能的错误。单元测试不是用来证明?zhn)是对的,而是Z(jin)证明(zhn)没有错?/p>

啊哈Q再ơ运行测试,l条又重现眼前。通过?WordDealUtil.wordFormat4DB 比较全面的单元测试,现在的代码已l比较稳定,可以作ؓ(f) API 的一部分提供l其它模块用了(jin)?/p>

不知不觉中我们已l?JUnit 漂亮的完成了(jin)一ơ单元测试。可以体?x)?JUnit 是多么轻量Q多么简单,Ҏ(gu)不需要花?j)思去研究Q这可以把更多的注意力攑֜更有意义的事情上——~写完整全面的单元测试?/p>


JUnit 深入

当然QJUnit 提供的功能决不仅仅如此简单,在接下来的内容中Q我们会(x)看到 JUnit 中很多有用的Ҏ(gu),掌握它们Ҏ(gu)灉|的编写单元测试代码非常有帮助?/p>

Fixture

何谓 Fixture Q它是指在执行一个或者多个测试方法时需要的一pd公共资源或者数据,例如试环境Q测试数据等{。在~写单元试的过E中Q?zhn)会(x)发现在大部分的试?gu)在进行真正的试之前都需要做大量的铺?#8212;—计准?Fixture 而忙。这些铺垫过E占据的代码往往比真正测试的代码多得多,而且q个比率随着试的复杂程度的增加而递增。当多个试Ҏ(gu)都需要做同样的铺垫时Q重复代码的“坏味?#8221;便在试代码中I漫开来。这?#8220;坏味?#8221;?x)弄脏(zhn)的代码,q会(x)因ؓ(f)疏忽造成错误Q应该用一些手D|栚w它?/p>

JUnit 专门提供?jin)设|公?Fixture 的方法,同一试cM的所有测试方法都可以q它来初始?Fixture 和注销 Fixture。和~写 JUnit 试Ҏ(gu)一P公共 Fixture 的设|也很简单,(zhn)只需要:(x)

  1. 使用注解 org,junit.Before 修饰用于初始?Fixture 的方法?/li>
  2. 使用注解 org.junit.After 修饰用于注销 Fixture 的方法?/li>
  3. 保证q两U方法都使用 public void 修饰Q而且不能带有M参数?

遵@上面的三条原则,~写出的代码大体是这个样子:(x)

 // 初始?Fixture Ҏ(gu)
 @Before public void init(){ …… } 

 // 注销 Fixture Ҏ(gu)
 @After public void destroy(){ …… } 

q样Q在每一个测试方法执行之前,JUnit ?x)保?init Ҏ(gu)已经提前初始化测试环境,而当此测试方法执行完毕之后,JUnit 又会(x)调用 destroy Ҏ(gu)注销试环境。注意是每一个测试方法的执行都会(x)触发对公?Fixture 的设|,也就是说使用注解 Before 或?After 修饰的公?Fixture 讄Ҏ(gu)是方法别的Q?a >?5Q。这样便可以保证各个独立的测试之间互不干扎ͼ以免其它试代码修改试环境或者测试数据媄(jing)响到其它试代码的准性?/p>
?5 Ҏ(gu)U别 Fixture 执行C意?/strong>
?5 Ҏ(gu)U别 Fixture 执行C意? src=

可是Q这U?Fixture 讄方式q是引来?jin)批评,因?f)它效率低下,特别是在讄 Fixture 非常耗时的情况下Q例如设|数据库链接Q。而且对于不会(x)发生变化的测试环境或者测试数据来_(d)是不?x)?jing)响到试Ҏ(gu)的执行结果的Q也没有必要针Ҏ(gu)一个测试方法重新设|一?Fixture。因此在 JUnit 4 中引入了(jin)cȝ别的 Fixture 讄Ҏ(gu)Q编写规范如下:(x)

  1. 使用注解 org,junit.BeforeClass 修饰用于初始?Fixture 的方法?/li>
  2. 使用注解 org.junit.AfterClass 修饰用于注销 Fixture 的方法?/li>
  3. 保证q两U方法都使用 public static void 修饰Q而且不能带有M参数?

cȝ别的 Fixture 仅会(x)在测试类中所有测试方法执行之前执行初始化Qƈ在全部测试方法测试完毕之后执行注销Ҏ(gu)Q?a >?6Q。代码范本如下:(x)

 // cȝ?Fixture 初始化方?
 @BeforeClass public static void dbInit(){ …… } 
	
 // cȝ?Fixture 注销Ҏ(gu)
	 @AfterClass public static void dbClose(){ …… } 


?6 cȝ?Fixture 执行C意?/strong>
?6 cȝ?Fixture 执行C意? src=

异常以及(qing)旉试

注解 org.junit.Test 中有两个非常有用的参敎ͼ(x)expected ?timeout。参?expected 代表试Ҏ(gu)期望抛出指定的异常,如果q行试q没有抛?gu)个异常,?JUnit ?x)认个测试没有通过。这为验证被试Ҏ(gu)在错误的情况下是否会(x)抛出预定的异常提供了(jin)便利。D例来_(d)Ҏ(gu) supportDBChecker 用于(g)查用户用的数据库版本是否在pȝ的支持的范围之内Q如果用户用了(jin)不被支持的数据库版本Q则?x)抛(gu)行时异?UnsupportedDBVersionException。测试方?supportDBChecker 在数据库版本不支持时是否?x)抛出指定异常的单元试?gu)大体如下Q?/p>
 @Test(expected=UnsupportedDBVersionException.class) 
	 public void unsupportedDBCheck(){ 
		……
 } 

注解 org.junit.Test 的另一个参?timeoutQ指定被试Ҏ(gu)被允许运行的最长时间应该是多少Q如果测试方法运行时间超q了(jin)指定的毫U数Q则 JUnit 认ؓ(f)试p|。这个参数对于性能试有一定的帮助。例如,如果解析一份自定义?XML 文档p?jin)多?1 U的旉Q就需要重新考虑 XML l构的设计,那单元测试方法可以这h写:(x)

 @Test(timeout=1000) 
	 public void selfXMLReader(){ 
		……
 } 

忽略试Ҏ(gu)

JUnit 提供注解 org.junit.Ignore 用于暂时忽略某个试Ҏ(gu)Q因为有时候由于测试环境受限,q不能保证每一个测试方法都能正运行。例如下面的代码便表C由于没有了(jin)数据库链接,提示 JUnit 忽略试Ҏ(gu) unsupportedDBCheckQ?/p>
 @ Ignore(“db is down”) 
 @Test(expected=UnsupportedDBVersionException.class) 
	 public void unsupportedDBCheck(){ 
		……
 } 

但是一定要心(j)。注?org.junit.Ignore 只能用于暂时的忽略测试,如果需要永q忽略这些测试,一定要认被测试代码不再需要这些测试方法,以免忽略必要的测试点?/p>

试q行?/span>

又一个新概念出现?#8212;—试q行器,JUnit 中所有的试Ҏ(gu)都是由它负责执行的。JUnit 为单元测试提供了(jin)默认的测试运行器Q但 JUnit q没有限制?zhn)必须使用默认的运行器。相反,(zhn)不仅可以定制自qq行器(所有的q行器都l承?org.junit.runner.RunnerQ,而且q可以ؓ(f)每一个测试类指定使用某个具体的运行器。指定方法也很简单,使用注解 org.junit.runner.RunWith 在测试类上显式的声明要用的q行器即可:(x)

 @RunWith(CustomTestRunner.class) 
 public class TestWordDealUtil { 
……
 } 

显而易见,如果试cL有显式的声明使用哪一个测试运行器QJUnit ?x)启动默认的试q行器执行测试类Q比如上面提?qing)的单元试代码Q。一般情况下Q默认测试运行器可以应对l大多数的单元测试要求;当?JUnit 提供的一些高U特性(例如卛_介绍的两个特性)(j)或者针对特D需求定?JUnit 试方式Ӟ昑ּ的声明测试运行器必不可了(jin)?/p>

试套g

在实际项目中Q随着目q度的开展,单元试cM(x)来多Q可是直到现在我们还只会(x)一个一个的单独q行试c,q在实际目实践中肯定是不可行的。ؓ(f)?jin)解册个问题,JUnit 提供?jin)一U批量运行测试类的方法,叫做试套g。这P每次需要验证系l功能正性时Q只执行一个或几个试套g便可以了(jin)。测试套件的写法非常单,(zhn)只需要遵循以下规则:(x)

  1. 创徏一个空cM为测试套件的入口?/li>
  2. 使用注解 org.junit.runner.RunWith ?org.junit.runners.Suite.SuiteClasses 修饰q个I类?/li>
  3. ?org.junit.runners.Suite 作ؓ(f)参数传入注解 RunWithQ以提示 JUnit 为此cM用套件运行器执行?/li>
  4. 需要放入此试套g的测试类l成数组作ؓ(f)注解 SuiteClasses 的参数?/li>
  5. 保证q个I类使用 public 修饰Q而且存在公开的不带有M参数的构造函数?
 package com.ai92.cooljunit; 

 import org.junit.runner.RunWith; 
 import org.junit.runners.Suite; 
……

 /** 
 * 扚w试 工具?中测试类
 * @author Ai92 
 */ 
 @RunWith(Suite.class) 
 @Suite.SuiteClasses({TestWordDealUtil.class}) 
 public class RunAllUtilTestsSuite { 
 } 

上例代码中,我们前文提到的试c?TestWordDealUtil 攑օ?jin)测试套?RunAllUtilTestsSuite 中,?Eclipse 中运行测试套Ӟ可以看到试c?TestWordDealUtil 被调用执行了(jin)。测试套件中不仅可以包含基本的测试类Q而且可以包含其它的测试套Ӟq样可以很方便的分层理不同模块的单元测试代码。但是,(zhn)一定要保证试套g之间没有循环包含关系Q否则无的循环׃(x)出现在?zhn)的面?#8230;…?/p>

参数化测?/span>

回顾一下我们在节“JUnit 初体?/a>”中D的实例。ؓ(f)?jin)保证单元测试的严}性,我们模拟?jin)不同类型的字符串来试?gu)的处理能力,为此我们~写大量的单元测试方法。可是这些测试方法都是大同小异:(x)代码l构都是相同的,不同的仅仅是试数据和期望倹{有没有更好的方法将试Ҏ(gu)中相同的代码l构提取出来Q提高代码的重用度,减少复制_脓(chung)代码的烦(ch)|在以前的 JUnit 版本上,q没有好的解x法,而现在?zhn)可以使?JUnit 提供的参数化试方式应对q个问题?/p>

参数化测试的~写E微有点ȝ(ch)Q当然这是相对于 JUnit 中其它特性而言Q:(x)

  1. 为准备用参数化试的测试类指定Ҏ(gu)的运行器 org.junit.runners.Parameterized?/li>
  2. 为测试类声明几个变量Q分别用于存放期望值和试所用数据?/li>
  3. 为测试类声明一个用注?org.junit.runners.Parameterized.Parameters 修饰的,q回gؓ(f) java.util.Collection 的公共静(rn)态方法,q在此方法中初始化所有需要测试的参数寏V?/li>
  4. 为测试类声明一个带有参数的公共构造函敎ͼq在其中为第二个环节中声明的几个变量赋倹{?/li>
  5. ~写试Ҏ(gu)Q用定义的变量作ؓ(f)参数q行试?

我们按照q个标准Q重新改造一番我们的单元试代码Q?/p>
package com.ai92.cooljunit; 

import static org.junit.Assert.assertEquals; 
import java.util.Arrays; 
import java.util.Collection; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.junit.runners.Parameterized; 
import org.junit.runners.Parameterized.Parameters; 

@RunWith(Parameterized.class) 
public class TestWordDealUtilWithParam { 

        private String expected; 
    
        private String target; 
    
        @Parameters 
        public static Collection words(){ 
            return Arrays.asList(new Object[][]{ 
                {"employee_info", "employeeInfo"},      // 试一般的处理情况
                {null, null},                           // 试 null 时的处理情况
                {"", ""},                               // 试I字W串时的处理情况
                {"employee_info", "EmployeeInfo"},      // 试当首字母大写时的情况
                {"employee_info_a", "employeeInfoA"},   // 试当尾字母为大写时的情?
                {"employee_a_info", "employeeAInfo"}    // 试多个相连字母大写时的情况
            }); 
        } 
    
         /** 
         * 参数化测试必ȝ构造函?
         * @param expected     期望的测试结果,对应参数集中的第一个参?
         * @param target     试数据Q对应参数集中的W二个参?
         */ 
        public TestWordDealUtilWithParam(String expected , String target){ 
            this.expected = expected; 
            this.target = target; 
        } 
    
         /** 
         * 试?Java 对象名称到数据库名称的{?
         */ 
        @Test public void wordFormat4DB(){ 
            assertEquals(expected, WordDealUtil.wordFormat4DB(target)); 
        } 
} 

很明显,代码瘦n?jin)。在?rn)态方?words 中,我们使用二维数组来构建测试所需要的参数列表Q其中每个数l中的元素的攄序q没有什么要求,只要和构造函C的顺序保持一致就可以?jin)。现在如果再增加一U测试情况,只需要在?rn)态方?words 中添加相应的数组卛_Q不再需要复制粘贴出一个新的方法出来了(jin)?/p>


JUnit ?Ant

随着目的进展,目的规模在不断的膨胀Qؓ(f)?jin)保证项目的质量Q有计划的执行全面的单元试是非常有必要的。但单靠 JUnit 提供的测试套件很难胜任这工作,因ؓ(f)目中单元测试类的个数在不停的增加,试套g却无法动态的识别新加入的单元试c,需要手动修Ҏ(gu)试套Ӟq是一个很Ҏ(gu)遗忘得步骤,E有疏忽׃(x)影响全面单元试的覆盖率?/p>

当然解决的方法有多种多样Q其中将 JUnit 与构建利?Ant l合使用可以很简单的解决q个问题。Ant —— 备受赞誉?Java 构徏工具。它凭借出色的易用性、^台无x以?qing)对目自动试和自动部|的支持Q成Z多项目构E中不可或缺的独立工Pq已l成Z实上的标准。Ant 内置?jin)?JUnit 的支持,它提供了(jin)两个 TaskQjunit ?junitreportQ分别用于执?JUnit 单元试和生成测试结果报告。用这两个 Task ~写构徏脚本Q可以很单的完成每次全面单元试的Q务?/p>

不过Q在使用 Ant q行 JUnit 之前Q?zhn)需要稍作一些配|。打开 Eclipse 首选项界面Q选择 Ant -> Runtime 首选项Q见 ?7Q,?JUnit 4.1 ?JAR 文gd?Classpath Tab 中?Global Entries 讄w。记得检查一?Ant Home Entries 讄中?Ant 版本是否?1.7.0 之上Q如果不是请替换为最新版本的 Ant JAR 文g?/p>
?7 Ant Runtime 首选项
?7 Ant Runtime 首选项

剩下的工作就是要~写 Ant 构徏脚本 build.xml。虽然这个过E稍嫌繁琐,但这是一件一x逸的事情。现在我们就把前面编写的试用例都放|到 Ant 构徏脚本中执行,为项?coolJUnit 的构本添加一下内容:(x)

 <?xml version="1.0"?> 
 <!-- ============================================= 
     auto unittest task    
     ai92                                                                
     ========================================== --> 
 <project name="auto unittest task" default="junit and report" basedir="."> 

		 <property name="output folder" value="bin"/> 

		 <property name="src folder" value="src"/> 
	
		 <property name="test folder" value="testsrc"/> 
	
		 <property name="report folder" value="report" /> 

		 <!-- - - - - - - - - - - - - - - - - - 
          target: test report folder init                      
         - - - - - - - - - - - - - - - - - --> 
		 <target name="test init"> 
			 <mkdir dir="${report folder}"/> 
		 </target> 
	
		 <!-- - - - - - - - - - - - - - - - - - 
          target: compile                      
         - - - - - - - - - - - - - - - - - --> 
		 <target name="compile"> 
			 <javac srcdir="${src folder}" destdir="${output folder}" /> 
			 <echo>compilation complete!</echo> 
		 </target> 

		 <!-- - - - - - - - - - - - - - - - - - 
          target: compile test cases                      
         - - - - - - - - - - - - - - - - - --> 
		 <target name="test compile" depends="test init"> 
			 <javac srcdir="${test folder}" destdir="${output folder}" /> 
			 <echo>test compilation complete!</echo> 
		 </target> 
	
		 <target name="all compile" depends="compile, test compile"> 
		 </target> 
	
		 <!-- ======================================== 
          target: auto test all test case and output report file                      
      	 ===================================== --> 
		 <target name="junit and report" depends="all compile"> 
			 <junit printsummary="on" fork="true" showoutput="true"> 
				 <classpath> 
					 <fileset dir="lib" includes="**/*.jar"/> 
					 <pathelement path="${output folder}"/> 
				 </classpath> 
				 <formatter type="xml" /> 
				 <batchtest todir="${report folder}"> 
					 <fileset dir="${output folder}"> 
						 <include name="**/Test*.*" /> 
					 </fileset> 
				 </batchtest> 
			 </junit> 
			 <junitreport todir="${report folder}"> 
				 <fileset dir="${report folder}"> 
					 <include name="TEST-*.xml" /> 
				 </fileset> 
				 <report format="frames" todir="${report folder}" /> 
			 </junitreport> 
		 </target> 
 </project> 

Target junit report ?Ant 构徏脚本中的核心(j)内容Q其?target 都是为它的执行提供前期服务。Task junit ?x)寻找输出目录下所有命名以“Test”开头的 class 文gQƈ执行它们。紧接着 Task junitreport ?x)将执行l果生成 HTML 格式的测试报告(?8Q放|在“report folder”下?/p>

为整个项目的单元试cȝ定一U命名风根{不仅是Z区分cd的考虑Q这?Ant 扚w执行单元试也非常有帮助Q比如前面例子中的测试类都已“Test”打头Q而测试套件则?#8220;Suite”l尾{等?/p>
?8 junitreport 生成的测试报?/strong>
?8 junitreport 生成的测试报? src=

现在执行一ơ全面的单元试变得非常单了(jin)Q只需要运行一?Ant 构徏脚本Q就可以走完所有流E,q能得到一份详的试报告。?zhn)可以?Ant 在线手册中获得上面提?qing)的每一?Ant 内置 task 的用细节?/p>


ȝ

随着来多的开发h员开始认同ƈ接受极限~程QXPQ的思想Q单元测试的作用在Y件工E中变得来重要。本文旨在将最新的单元试工具 JUnit 4 介绍l?zhn)Q以?qing)如何结?IDE Eclipse 和构建工?Ant 创徏自动化单元测试方案。ƈ且还期望(zhn)能够通过本文“感染”一些好的单元测试意识,因ؓ(f) JUnit 本n仅仅是一份工兯(g)已Q它的真正优势来自于它的思想和技术?/p>

]]>
վ֩ģ壺 | ˰| ɽ| | ٳ| Ī| | | | Ͽ| | ̨ǰ| ԫ| ɽ| Ϫ| ¦| | | | | | | ɽ| | | ˮ| ˳| ƺ| | | »| | | | | | ɽ| ¦| Ϫ| ƽ| Ͷ|