??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲色婷婷综合久久,亚洲精品综合久久中文字幕 ,午夜亚洲福利在线老司机http://m.tkk7.com/jackybu/category/966.html<a ><b><font color=red>共有<script src=http://fastonlineusers.com/online.php?d=jackybu.blogjava.net></script>人在同时阅读此Blog</font></b></a>zh-cnFri, 02 Mar 2007 03:30:21 GMTFri, 02 Mar 2007 03:30:21 GMT60版本控制工具 http://m.tkk7.com/jackybu/articles/3139.html?/dc:creator>?/author>Mon, 11 Apr 2005 06:47:00 GMThttp://m.tkk7.com/jackybu/articles/3139.htmlhttp://m.tkk7.com/jackybu/comments/3139.htmlhttp://m.tkk7.com/jackybu/articles/3139.html#Feedback0http://m.tkk7.com/jackybu/comments/commentRss/3139.htmlhttp://m.tkk7.com/jackybu/services/trackbacks/3139.html版本控制工具
    版本控制是程序开发、管理必不可的工具Q特别是在多人协作的团队中,适宜的版本控制工具可以提高开发效率,消除很多有代码版本带来的问题。本文首先列举没有版本控制工h可能遇到的问题,再对L版本控制工具做概要介l,之后对作为Java开发者首选的版本控制工具CVS的历双Ӏ功能、概念做详细的介l;最后在EclipseQCVS环境中,以CVS使用的一个完整流Eؓ例,介绍如何正确的用CVS工具?BR>
Z么要使用版本控制工具Q?/STRONG>
如果没有版本控制工具的协助,在开发中我们l常会遇C面的一些问题:
一?nbsp;代码理混ؕ。如果是别hd或删除一个文Ӟ你很隑֏现。没有办法对文g代码的修改追查跟t。甚臛_现文件丢失,或新版本代码被同伴无意覆盖等现象?BR>二?nbsp;解决代码冲突困难。当大家同时修改一个公共文件时Q解决代码冲H是一件很头疼的事。最原始的办法是手工打开冲突文gQ逐行比较Q再手工_脓(chung)复制。更高的做法是使用文g比较工具Q但仍省不了J杂的手工操作,一不小心,甚至会引入新的bug?BR>三?nbsp;在代码整合期间引入深层BUG。例如开发者A写了一个公共函敎ͼB觉得正好可以复用Q后来A又对q个公共函数q行了修改,d了新的逻辑Q而这个改动的却是B不想要的。或者是A发现q个公共函数不够用,又新做了一个函敎ͼB却没有及时获得通知。这些,都ؓ深层BUG留下隐?zhn)?BR>四?nbsp;无法对代码的拥有者进行权限控制。代码完全暴露在所有的开发者面前,M人都可以随意q行增、删、改操作Q无法指定明的人对代码q行负责。特别是产品的开发,q是极其危险的?BR>五?nbsp;目不同版本发布困难。特别是对品的开发,你会频繁的进行版本发布,q时如果没有一个有效的理产品版本的工P一切将变得非常艰难?BR>    上面只是列D了一些没有版本控制系l可能带来的问题Q特别是对大型项目和异地协同开发有了一个合适的版本控制工具Q它可以有效解决因ؓ代码版本不同引v的各U问题,让我们的开发h员能更多的把_֊p在开发上面。而不是每ơ都p很多旉q行代码整合和解决版本不同带来的各种问题?/P>

L版本控制工具介绍
    现在Q有很多优秀的版本控制工具供我们选择Q下面就五种L的版本控制工具做单的介绍?BR>Starteam
    是一个集合了版本控制、构建管理(Build ManagementQ和~陷跟踪pȝZ体的软gQƈ且具有强大的囑Ş界面Q易学易用;但管理复杂、维护困难?002q底被Borland公司收购?BR>PVCS Version Manager
     是美国的MERANT公司软g配置理工具PVCS 家族中的一个组成部分,它能够实现源代码、可执行文g、应用文件、图形文件和文档的版本管理;它能安全地支持Y件ƈ行开发,对多个Y件版本的变更q行有效的控制管理?BR>ClearCase(CC)
    是ROSE构g的一部分Q目前最牛的配置理工具Q主要应用于复杂的品发放、分布式团队合作、ƈ行的开发和l护d。可以控制word, excel,powerpointQvisio{文件格式,对于不认识的格式可以自己定义一U类型来标识?BR>Visual SourceSafeQVSSQ?BR>    单易用、方侉K效、与Windows操作pȝ及微软开发工具高度集成?BR>CVSQConcurrent Versions SystemQ?BR>    是开发源码的q发版本pȝ,它是目前最行的面向Y件开发h员的源代码版本管理解x案。它可用于各U^収ͼ包括 Linux 、Unix?Windows NT/2000/XP{等?BR>    前面三种是重量的商业版本控制工P更适合庞大的团队和目Qƈ且h(hun)g菌ӀVisual SourceSafe是微软的产品Q当然只能用在windowsq_q与微Y的开发工h~集成。CVS免费开源,q且几乎所有开源项目都是用CVSq行版本理Q无疑,它是我们Java开发者最优选择?BR>
CVS的历双Ӏ功能、基本概늚介绍

历史

    CVS 诞生?1986 q_当时作ؓ一l?shell 脚本而出玎ͼ1989q?月,Brian Berlinor用C语言重新设计q编写了CVS的代码;1993q前后,Jim Kingdon最l将CVS设计成基于网l的q_Q开发者们能从InternetM地方获得E序源代码。截至目前最新版本是2004q?2?3日发布的1.12.11?BR>
功能介绍
一?nbsp;代码l一理Q保存所有代码文件更改的历史记录。对代码q行集中l一理Q可以方便查看新增或删除的文Ӟ能够跟踪所有代码改动痕qV可以随意恢复到以前L一个历史版本。ƈ避免了因为版本不同引入的深层BUG?BR>二?nbsp;完善的冲H解x案,可以方便的解x件冲H问题,而不需要借助其它的文件比较工具和手工的粘贴复制?BR>三?nbsp;代码权限的管理。可以ؓ不同的用戯|不同的权限。可以设|访问用L(fng)密码、只诅R修改等权限Q而且通过CVS ROOT目录下的脚本Q提供了相应功能扩充的接口,不但可以完成_的权限控Ӟq能完成更加个性化的功能?BR>四?nbsp;支持方便的版本发布和分支功能?/P>

基本概念
资源库(RepositoryQ?/STRONG>
CVS的资源库存储全部的版本控制下的文件copyQ通常不容许直接访问,只能通过cvs命oQ获得一份本地copyQ改动后再check inQcommitQ回资源库。而资源库通常Z工作目录分离的。CVS通过多种方式讉K资源库。每U方法有不同目录表示形式?BR>版本QRevisionQ?/STRONG>
每一个文件的各个版本都不相同QŞ?.1, 1.2.1,一?.1是该文g的第一个revisionQ后面的一个将自动增加最右面的一个整敎ͼ比如1.2, 1.3, 1.4...有时候会出现1.3.2.2Q原因见后。revisionL偶数个数字。一般情况下revision看作时CVS自己内部的一个编P而tag则可以标志用L(fng)特定信息?BR>标签QTagQ?/STRONG>
用符号化的表C方法标志文件特定revision的信息。通常不需要对某一个孤立的文g作tagQ而是Ҏ(gu)有文件同时作一个tagQ以后用户可以仅向特定tag的文件提交或者checkout。另外一个作用是在发布Y件的时候表C哪些文件及其哪个版本是可用的;各文件不同revision可以包括在一个tag中。如果命名一个已存在的tag默认不会覆盖原来的Q?BR>分支QBranchQ?BR>当用户修改一个branch时不会对另外的branch产生M影响。可以在适当的时候通过合ƈ的方法将两个版本合v来;branchL在当前revision后面加上一个偶数整敎ͼ?开始,?l束Q,所以branchL奇数个数字,比如1.2后面branch?.2.2Q该分支下revision可能?.2.2.1,1.2.2.2,...
冲突QConflctQ?BR>完全是纯文本的冲H,不包含逻辑上的矛盾。一般是一份文ӞA做了改动QB在A提交之前也做了改动,q样最后谁commit׃出现冲突Q需要手工解军_H再提交?BR>
CVS与eclipse集成开?/STRONG>
  前面对CVS的历双Ӏ功能、概论等理论知识做了介绍。下面我们将使用最行的Java IDE Eclipse中内|的CVS工具Q以一个完整开发流E,介绍实际环境中CVS的正用。关于CVSpȝ的安装,不是本文的内容,(zhn)可以从附录的链接中获取安装的介l资料?BR>
常用的CVS控制命o
Check OutQ检出)
把源文g从cvs源代码仓库中取出Q缺省的版本是最新的版本Q你也可以选择指定的版本。在每次更改源代码之前,需要Check Out最新的版本Q再起基之上Ҏ(gu)代码q行修改。将代码目录checkout到指定目录下Q所有文仉是read-write?BR>Check InQ检入)
把源代码加入到cvs源代码仓库中Q每一个添加进代码库中的文件的版本?1.1。以后每ơ修Ҏ(gu)仉新ci以后Q此文g的版本递增?.2 Q?.3.……。在每次Ҏ(gu)代码修改之后Q需要Check InQ提交最新版本的源代码?BR>Synchronize with Repository(与资源库同步Q简U同?
使本地更改与资源库同步,它会列出本地和资源库之间不同的所有文件?BR>Add to Version Control
新的文件加入到版本控制之中?BR>Add to .cvsIgnore
文件设|到版本控制之外Q这栯文g或目录中的文件的更改在CVS中不可见Q即使同步也无法发现?/P>

CVS正确使用步骤
一?nbsp;同步QSynchronizeQ?/STRONG>
是本地更改与服务器同步,同步之后可以清晰的看C一捡出QCheck OutQ版本之后本地、服务器上的最新改动。这是非常有用的Q特别是敏捷开发,集体拥有代码。有了同步功能,你可以全局把握目的代码,可以很方便的跟踪公共模块代码的Q何改动?BR>具体操作Q在Eclipse的资源视图(Resource PerspectiveQ或者Java视图QJava PerspectiveQ中Q选中要同步的目录Q点d键选择"Synchronize with Repository",之后它将昄同步的视图。如下图Q?BR> 
(图一、CVS同步视图)
同步之后Q它有四UMode可以选择Q见上图l色框框里按钮。从做到叛_别ؓQ?BR>Incoming ModeQ表CZҎ(gu)来自服务器,对应于更斎ͼupdateQ操作?BR>Outgoing ModeQ表CZҎ(gu)来自本地Q对应提交(commitQ操作?BR>Incoming/ Outgoing ModeQ本地和服务器修攚w在该模式QModeQ中昄?BR>Conflicts ModeQ显C本地和服务器修改的冲突文g?BR>二?nbsp;更新QupdateQ?BR>比较单,选择Incoming ModeQ再选中要更新的文gQ右键选择update操作?BR>三?nbsp;解决冲突q合q?solve conflct and merge)
如果有冲H文Ӟ冲突文g不能更新。你必须先解军_H再操作。选中冲突的文Ӟ再点右键选择"Open in Compare Editor"Q用比较工具打开该文件。如下图Q?

Q图二、CVS比较器视图)

比较器(CompareQ视图,左边版本底的是本地文ӞLocal FileQ,双是远E服务器文gQRemote FileQ。?Select Next Change"按钮Q绿框中的第一头向下按钮Q,逐一查看不同炏V如果不同点标识为黑色框框,则不用管它。如果是蓝色框框Q则需要手工调整。如上图Q不同点是蓝色框框,鼠标放C个不同点的中间小Ҏ(gu)中,则凸Z个向右的按钮Qƈ昄提示信息"Copy Current Change from Right to Left"Q意思是右Ҏ(gu)务器的不同点覆盖到左边的本地文g。点中此按钮。重复这L(fng)操作Q将所有服务器上的更改拯到本地?BR>如果有一行代码,本地和服务器都同时做了修攏V这Ӟ修改点则昄U色框框。这Ӟ你就必须手工做正的修改。全部修改完成,保存本地文g?BR>此时Q如果修改点没有了蓝色的框框Q就可以开始做合ƈQmergeQ操作了。操作也很简单,选择该文Ӟ点击右键Q选择"Mark as merged"?BR>注意Q必ȝ保没有蓝色框框,卛_全拷贝了服务器的修改才可以做合ƈQmergeQ操作,否则会覆盖服务器上的代码?BR>四?nbsp;提交QcommitQ?BR>更新服务器代码,解决冲突之后Q首先要查看本地文g修改之后是否有错误。如果有Q当焉先解决错误,再提交?BR>
附录Q?/STRONG>
http://www.8848software.com/scmchina/scmtools.htm 由很多版本控制工L(fng)文档链接?BR>http://www.perforce.com/perforce/reviews.html Infrastructure Group对Perforce 和Clearcase, CVS, PVCS,Visual SourceSafe (VSS)几种CM工具q行了定量和定性的比较. 对于定性的比较Q内Ҏ(gu)及工h持的Ҏ(gu)和环境;对于定量的比较,包括在不同的目规模上,执行不同的活动所需要的旉?BR>




]]>
单元试Q入门篇 http://m.tkk7.com/jackybu/articles/3138.html?/dc:creator>?/author>Mon, 11 Apr 2005 06:46:00 GMThttp://m.tkk7.com/jackybu/articles/3138.htmlhttp://m.tkk7.com/jackybu/comments/3138.htmlhttp://m.tkk7.com/jackybu/articles/3138.html#Feedback0http://m.tkk7.com/jackybu/comments/commentRss/3138.htmlhttp://m.tkk7.com/jackybu/services/trackbacks/3138.html前面的一文章(单元试Q理论篇Q讨Z什么是单元试、单元测试的优点q列举了很多不写单元试的借口。如果你同意我们的观点,认同单元试实是Y件开发中不可~少的过E,那么我们开始单元测试之旅吧Q?/P>


一个比较最大值的函数
  我们首先引入一个比较最大值的函数。我们传入一个类型ؓint的数l参敎ͼ它将q回最大值的那个元素。代码如下:
public class Largest {
 public static int largest(int[] datas){
  int max = 0;
  
  for(int i = 0 ; i < datas.length ; i++){
   if(max < datas[i]){
    max = datas[i];
   }
  }
  return max;
 }
}
  可是Q如何写我们的测试代码呢Q?/P>


直接在LargestcMd一个mainҎ(gu)Q要么重新写一个可q行的类来测试Largest。这L(fng)试Q同L(fng)我们带来了很大的挑战Q?BR>1?nbsp;验证困难。如何去验证代码的行为和我们的期望一致呢Q用很多的if…else再加上=Q或equals()来判断?对异常的情况又如何处理呢Q؜q验证Q很Ҏ(gu)l我们的试代码带来BUGQ让我们对自q试不够自信?BR>2?nbsp;试cL法管理。我们如何直观的得到试q行成功或失败的消息?用原始的System.out.println()吗?我们能一ơ运行多个单元测试吗Q如果前面的试q行出现异常Q后面的试q能l箋q行吗?如果试cd多,上百个甚x多,我们能方便的由控制台输出试l果吗?
3?nbsp;无法l计试代码覆盖情况。缺统一的测试代码编写规范和U定Q可L和l护性差?BR>不过Q面对这些挑战不用沮丧。单元测试框架已l帮我们解决了这些问题,它提供了很多试的基设施Q让我们能把更多的经历投入到试代码的编写中来?/P>


JUnit
JUnit最初是由Erich GammaQGoF之一Q和Kent BeckQxp和refactor的先׃一Q编写的Q它是一个开源的Java试框架Q用于编写和q行可重复的试?/P>


下面我们逐步介绍如何对LargestcL试:
一?nbsp;JUnit的安装。如果你使用的开发工hEclipseQ不用做M安装Q它已经提供了Junit的支持。否则,你需要去http://www.junit.org/ 下蝲Junit安装包。安装非常简单,只要junit.jar包设|到ClassPath中,让你的Java代码能够扑ֈ它就可以了?BR>二?nbsp;~写试代码。代码如下:
    public class LargestTest extends TestCase {
  public void testLargest(){
   int[] datas = {7,8,9};
   assertEquals(9,Largest.largest(datas));
  }
}
说明Q?BR>1?nbsp;试cM般要l承抽象cTestCase。它实现了各U测试方法,q提供了一个测试过E的架构?BR>2?nbsp;试代码通过断言QAssertQ来判断某个被测试函数是否正常工作。JUnit提供了很多断a函数Q用来确定:某个条g是否为真Q两个数据是否相{,或者不{,或者其它的一些情c?BR>3?nbsp;试Ҏ(gu)名以“test”开_q样JUnit框架会自动发现这是一个测试方法?/P>

三?nbsp;q行试cR?BR>   q行试成功?/P>

我们的单元测试这样就完成了吗?不,上面的测试只能算是一ơ验证而已。我们给的数据中Q最大?是数l的最后一个元素,如果9是第一个元素它q正吗Q如果数据是负数呢?{等。我们的求最大值函数有着很多的边界情况需要单元测试来验证?BR>   因此Q我们在写单元测试之前,一定要Ҏ(gu)试做一个周全的计划Q预先设|好要测试的内容Q可能发生错误的边界条g?BR>下面是对Largest做的试计划Q?BR>1?nbsp;数组元素的位|是否对最大g生媄响?
l [7,8,9] ?9
l [7,9,8] ?9
l [9,8,7] ?9
2?nbsp;如果有两个相{的最大|会出C么情况呢Q?BR>l [7,9,8,9] ?9
3、如果数l中只有一个元素,l果会怎么P
l [1] - 1
4?nbsp;如果元素都是负数呢?
l [-7,-8,-9] - -7
完整的测试代码应该如下:
public class LargestTest extends TestCase {
 
 public void testSimple(){
  assertEquals(9,Largest.largest(new int[]{7,8,9}));
 }
 public void testOrder(){
  assertEquals(9,Largest.largest(new int[]{7,9,8}));
  assertEquals(9,Largest.largest(new int[]{9,8,7}));
 }
 public void testDups(){
  assertEquals(9,Largest.largest(new int[]{7,9,8,9}));
 }
 public void testOne(){
  assertEquals(1,Largest.largest(new int[]{1}));
 }
 public void testNegative(){
   assertEquals(-7,Largest.largest(new int[]{-7,-8,-9}));
 }
}
当然Q你可以写完一个测试方法就立即来运行它。这ơƈ没有那么q运了,在运行最后一个测试方法testNegative()时出C错误Q?BR>junit.framework.AssertionFailedError: expected:<-7> but was:<0>
 at test.junit.LargestTest.testNegative(LargestTest.java:24)
l心的你Q也许在一开始就发现了Largest的这个Bug。原来我们的字段max初始化ؓ0是不对的Q应该改为Integer.MIN_VALUE?BR>由此我们可以惛_Q用单元测试确实可以尽早的发现隐藏的BUGQ上一我们也说过Q越早发现BUGp节省更多的时_降低更多的风险?BR>q是Q我们的单元试已经完美l束了吗Q呵呵,也许你会惛_Q如果在largest()Ҏ(gu)中传入数lؓI,又会怎么样呢Q这个问题留l我们的读者思考吧?/P>


写到q里Q算是入门结束了吧!关于JUnit的详l介l,|上有非常多的文章,去google你可以找C大堆。下面我提供几个不错的单元测试网站,希望能对你有所帮助Q?BR>51Testing-无忧软g试|:http://www.51testing.com/
试时代Q?A >http://www.testage.net/
UML软g工程l织QY件测试:http://www.uml.org.cn/Test/test.asp
试理中心Q?A >http://www.testmanager.com.cn/
软g工程专家|:http://www.51cmm.com/
开放Y件测试研IӞhttp://www.opentest.net/



]]>
单元试Q理论篇 http://m.tkk7.com/jackybu/articles/3137.html?/dc:creator>?/author>Mon, 11 Apr 2005 06:45:00 GMThttp://m.tkk7.com/jackybu/articles/3137.htmlhttp://m.tkk7.com/jackybu/comments/3137.htmlhttp://m.tkk7.com/jackybu/articles/3137.html#Feedback0http://m.tkk7.com/jackybu/comments/commentRss/3137.htmlhttp://m.tkk7.com/jackybu/services/trackbacks/3137.html作者:Moxie

        试是Y件开发的重要环节之一。按照Y件开发的q程试可分为:单元试、集成测试、系l测试、域试QField testQ等。我们这里将讨论面向E序员的单元试。本文首先介l单元测试的定义Qؓ什么要使用单元试Q单元测试能l我们带来的好处。之后我们将介绍单元试的范_最后将讨论很多朋友不写单元试的借口。希望本文能够再ơ引h对单元测试的重视Qƈ说服(zhn)老板对编写单元测试的支持Q能让美丽的单元试真正应用到?zhn)的项目之中?BR>
什么是单元试
      单元试是开发者编写的一段代码Q用于检验被代码的一个很的、很明确的功能是否正。通常而言Q一个单元测试是用于判断某个特定条gQ或者场景)下某个特定函数的行ؓ。例如,你可能把一个很大的值放入一个有序list 中去Q然后确认该值出现在list 的尾部。或者,你可能会从字W串中删除匹配某U模式的字符Q然后确认字W串实不再包含q些字符了?BR>    单元试是由E序员自己来完成Q最l受益的也是E序员自己。可以这么说Q程序员有责ȝ写功能代码,同时也就有责Mؓ自己的代码编写单元测试。执行单元测试,是Z证明q段代码的行为和我们期望的一致?BR>
Z么要使用单元试
    我们~写代码Ӟ一定会反复调试保证它能够编译通过。如果是~译没有通过的代码,没有MZ愿意交付l自q老板。但代码通过~译Q只是说明了它的语法正确Q我们却无法保证它的语义也一定正,没有M人可以轻易承D代码的行ؓ一定是正确的?BR>    q运Q单元测试会为我们的承诺做保证。编写单元测试就是用来验证这D代码的行ؓ是否与我们期望的一致。有了单元测试,我们可以自信的交付自q代码Q而没有Q何的后顾之忧?BR>
单元试有下面的q些优点Q?/STRONG>
1、它是一U验证行为?BR>    E序中的每一功能都是测试来验证它的正确性。它Z后的开发提供支~。就是开发后期,我们也可以轻杄增加功能或更改程序结构,而不用担心这个过E中会破坏重要的东西。而且它ؓ代码的重构提供了保障。这P我们可以更自由的对E序q行改进?BR>2、它是一U设计行为?BR>    ~写单元试我们从调用者观察、思考。特别是先写试Qtest-firstQ,q我们把程序设计成易于调用和可试的,卌使我们解除Y件中的耦合?BR>3、它是一U编写文档的行ؓ?BR>    单元试是一U无L(fng)文档Q它是展C函数或cd何用的最x档。这份文档是可编译、可q行的,q且它保持最斎ͼ永远与代码同步?BR>4、它h回归性?BR>    自动化的单元试避免了代码出现回归,~写完成之后Q可以随旉地的快速运行测试?

单元试的范?BR>    如果要给单元试定义一个明的范畴Q指出哪些功能是属于单元试Q这g很难。但下面讨论的四个问题,基本上可以说明单元测试的范畴Q单元测试所要做的工作?BR>1?nbsp;它的行ؓ和我期望的一致吗Q?/STRONG>
    q是单元试最Ҏ(gu)的目的,我们是用单元测试的代码来证明它所做的是我们所期望的?BR>2?nbsp;它的行ؓ一直和我期望的一致吗Q?/STRONG>
    ~写单元试Q如果只试代码的一条正\径,让它正确C遍,q不是真正的完成。Y件开发是一个项复杂的工E,在测试某D代码的行ؓ是否和你的期望一致时Q你需要确认:在Q何情况下Q这D代码是否都和你的期望一_譬如参数很可疑、硬盘没有剩余空间、缓冲区溢出、网l掉U的时候?BR>3?nbsp;我可以依赖单元测试吗Q?/STRONG>
   不能依赖的代码是没有多大用处的。既然单元测试是用来保证代码的正性,那么单元试也一定要值得依赖?BR>4?nbsp;单元试说明我的意图了吗Q?/STRONG>
    单元试能够帮我们充分了解代码的用法Q从效果上而言Q单元测试就像是能执行的文档Q说明了在你用各U条件调用代码时Q你所能期望这D代码完成的功能?BR>
不写试的借口
    到这里,我们已经列D了用单元测试的U种理由。也许,每个人都同意Q是的,该做更多的测试。这Uh人同意的事情q多着呢,是的Q该多吃蔬菜Q该戒烟Q该多休息,该多ȝ……这q不意味着我们中的所有h都会q么dQ不是吗Q?BR>1?nbsp;~写单元试太花旉了?/STRONG>
    我们知道Q在开发时早发现BUGQ就能节省更多的旉Q降低更多的风险?BR>    下图表摘?lt;<实用软g度量>>(Capers JonesQMcGraw-Hill 1991)Q它列出了准备测试,执行试Q和修改~陷所p的时?以一个功能点为基?Q这些数据显C单元测试的成本效率大约是集成测试的两倍,是系l测试的三?参见条Ş??BR> 
    术语Q域试(Field test)意思是在Y件投入用以后,针对某个领域所作的所有测试活动?BR>    如果你仍然认为在~写产品代码的时候,q是没有旉~写试代码Q那么请先考虑下面q些问题Q?BR>        1Q、对于所~写的代码,你在调试上面׃多少旉?BR>        2Q、对于以前你自认为正的代码Q而实际上q些代码却存在重大的bugQ你׃多少旉在重新确认这些代码上面?BR>        3Q、对于一个别人报告的bugQ你׃多少旉才找出导致这个bug 的源码位|?BR>    回答完这些问题,你一定不再以“太花时间”作为拒l单元测试的借口?BR>2?nbsp;q行试的时间太长了?/STRONG>
    合适的试是不会让q种情况发生的。实际上Q大多数试的执行都是非常快的,因此你在几秒之内可以运行成千上万个试。但是有时某些测试会p很长的时间。这Ӟ需要把q些耗时的测试和其他试分开。通常可以每天q行q种试一ơ,或者几天一ơ?BR>3?nbsp;试代码q不是我的工作?/STRONG>
    你的工作是保证代码能够正确的完成你的行为,恰恰相反Q测试代码正是你不可~少的工作?BR>4?nbsp;我ƈ不清楚代码的行ؓQ所以也无从测试?/STRONG>
   如果你实在不清楚代码的行为,那么估计现在q不是编码的时候。如果你q不知道代码的行为,那么你又如何知道你编写的代码是正的?
5?nbsp;但是q些代码都能够编译通过?/STRONG>
    我们前面已经说过Q代码通过~译只是验证它的语法通过。但q不能保证它的行为就一定正?BR>6?nbsp;公司h来是Z写代码,而不是写试?/STRONG>
    公司付给你薪水是Z让你~写产品代码Q而单元测试大体上是一个工P是一个和~辑器、开发环境、编译器{处于同一位置的工兗?BR>7?nbsp;如果我让试员或者QAQQuality AssuranceQh员没有工作,那么我会觉得很内疚?/STRONG>
   你ƈ不需要担心这些。请CQ我们在此只是谈论单元测试,而它只是一U针Ҏ(gu)码的、低层次的,为程序员而设计的试。在整个目中,q有其他的很多测试需要这些h来完成,如:功能试、验收测试、性能试、环境测试、有效性测试、正性测试、正规分析等{?BR>8?nbsp;我的公司q不会让我在真实pȝ中运行单元测试?BR>    我们所讨论的只是针对开发者的单元试。也是_如果你可以在其他的环境下Q例如在正式的品系l中Q运行这些测试的话,那么它们׃再是单元试Q而是其他cd的测试了。实际上Q你可以在你的本行单元测试,使用你自q数据库,或者用mock 对象?BR>
ȝ
  总而言之,单元试会让我们的开发工作变得更加轻松,让我们对自己的代码更加自信。无论是大型目q是型目Q无论是旉紧迫的项目还是时间宽裕的目Q只要代码不是一ơ写完永不改动,~写单元试׃定超|它已成ؓ我们~码不可~少的一部分?BR>
参考资?BR>《单元测试之道Java版——用JUNIT》:q是一本非常好的介l单元测试的书,作者讲的非帔R彻Q译者的文笔也很好。在此向(zhn)强烈推荐。本文内容,也有很多直接引用于此书!
《JUNIT IN ACTION》:q是一本专门介lJUNIT的好书?BR>



]]>
Junit学习(fn)W记http://m.tkk7.com/jackybu/articles/2898.html?/dc:creator>?/author>Thu, 07 Apr 2005 02:44:00 GMThttp://m.tkk7.com/jackybu/articles/2898.htmlhttp://m.tkk7.com/jackybu/comments/2898.htmlhttp://m.tkk7.com/jackybu/articles/2898.html#Feedback0http://m.tkk7.com/jackybu/comments/commentRss/2898.htmlhttp://m.tkk7.com/jackybu/services/trackbacks/2898.htmlJUnit是由 Erich Gamma ?Kent Beck ~写的一个回归测试框Ӟregression testing frameworkQ?供Java开发h员编写单元测试之用?A name=more>

1、概q?/STRONG>
  Junit试是程序员?gu)试Q即所谓白盒测试,因ؓE序员知道被试的Y件如何(HowQ完成功能和完成什么样QWhatQ的功能?BR>  Junit本质上是一套框Ӟ卛_发者制定了一套条条框框,遵@q此条条框框要求~写试代码Q如l承某个c,实现某个接口Q就可以用Junitq行自动试了?BR>  ׃Junit相对独立于所~写的代码,可以试代码的编写可以先于实C码的~写QXP 中推崇的 test first design的实现有了现成的手段Q用Junit写测试代码,写实C码,q行试Q测试失败,修改实现代码Q再q行试Q直到测试成功。以后对代码的修改和优化Q运行测试成功,则修Ҏ(gu)功?BR>  Java 下的 team 开发,采用 cvs(版本控制) + ant(目理) + junit(集成试) 的模式时Q通过对ant的配|,可以很简单地实现试自动化?/P>

  对不同性质的被对象,如ClassQJspQServletQEjb{,Junit有不同的使用技巧,以后慢慢地分别讲叙。以下以Class试Z讲解Q除非特D说明?/P>

2、下载安?/STRONG>
junit-alltest.gif

  • ?A >Junit主页下蝲最新版?.8.1E序包junit-3.8.1.zip
  • 用winzip或unzipjunit-3.8.1.zip解压~到某一目录名ؓ$JUNITHOME
  • junit.jar?JUNITHOME/junit加入到CLASSPATH中,加入后者只因ؓ试例程在那个目录下?BR>
  • 注意不要junit.jar攑֜jdk的extension目录?/INS>
  • q行命o,l果如右图?
    java junit.swingui.TestRunner junit.samples.AllTests

3、Junit架构
  下面以Moneyq个cMؓ例进行说明?

public class Money {
    private int fAmount;//余额
    private String fCurrency;//货币cd

    public Money(int amount, String currency) {
        fAmount= amount;
        fCurrency= currency;
    }

    public int amount() {
        return fAmount;
    }

    public String currency() {
        return fCurrency;
    }
    
    public Money add(Money m) {//加钱
        return new Money(amount()+m.amount(), currency());
    }
    
    public boolean equals(Object anObject) {//判断钱数是否相等
        if (anObject instanceof Money) {
            Money aMoney= (Money)anObject;
            return aMoney.currency().equals(currency())
                && amount() == aMoney.amount();
        }
        return false;
    }    
}


  Junit本n是围l着两个设计模式来设计的Q?ACRONYM title="command pattern">命o模式?ACRONYM title="composite pattern">集成模式.
  • 命o模式
      利用TestCase定义一个子c,在这个子cM生成一个被试的对象,~写代码某?ACONYM title=method>Ҏ(gu)被调用后对象的状态与预期的状态是否一_q?ACRONYM title=assert>断言E序代码有没有bug?BR>  当这个子c要试不只一?ACRONYM title=method>Ҏ(gu)的实C码时Q可以先建立试基础Q让q些试在同一个基上运行,一斚w可以减少每个试的初始化Q而且可以试q些不同Ҏ(gu)之间的联pR?BR>  例如Q我们要试Money的AddҎ(gu)Q可以如?
    public class MoneyTest extends TestCase { //TestCase的子c?/INS>
        public void testAdd() { //把测试代码放在testAdd?/INS>
            Money m12CHF= new Money(12, "CHF");  //本行和下一行进行一些初始化
            Money m14CHF= new Money(14, "CHF");        
            Money expected= new Money(26, "CHF");//预期的结?/INS>
            Money result= m12CHF.add(m14CHF);    //q行被测试的Ҏ(gu)
            Assert.assertTrue(expected.equals(result));     //判断q行l果是否与预期的相同
        }
    }

      如果试一下equalsҎ(gu)Q用cM的代码,如下Q?
    public class MoneyTest extends TestCase { //TestCase的子c?/INS>
        public void testEquals() { //把测试代码放在testEquals?/INS>
            Money m12CHF= new Money(12, "CHF"); //本行和下一行进行一些初始化
            Money m14CHF= new Money(14, "CHF");

            Assert.assertTrue(!m12CHF.equals(null));//q行不同情况的测?/INS>
            Assert.assertEquals(m12CHF, m12CHF);
            Assert.assertEquals(m12CHF, new Money(12, "CHF")); // (1)
            Assert.assertTrue(!m12CHF.equals(m14CHF));
        }
    }


      当要同时q行试Add和equalsҎ(gu)Ӟ可以它们的各自的初始化工作Q合q到一赯行,形成试基础,用setUp初始化,用tearDown清除。如下:
    public class MoneyTest extends TestCase {//TestCase的子c?/INS>
        private Money f12CHF;//提取公用的对?/INS>
        private Money f14CHF;   

        protected void setUp() {//初始化公用对?/INS>
            f12CHF= new Money(12, "CHF");
            f14CHF= new Money(14, "CHF");
        }
        public void testEquals() {//试equalsҎ(gu)的正?BR>        Assert.assertTrue(!f12CHF.equals(null));
            Assert.assertEquals(f12CHF, f12CHF);
            Assert.assertEquals(f12CHF, new Money(12, "CHF"));
            Assert.assertTrue(!f12CHF.equals(f14CHF));
        }
        
        public void testSimpleAdd() {//试addҎ(gu)的正?BR>        Money expected= new Money(26, "CHF");
            Money result= f12CHF.add(f14CHF);
            Assert.assertTrue(expected.equals(result));
        }
    }


      以上三个中的Q一个TestCase子类代码保存到名为MoneyTest.java的文仉Qƈ在文仉行增?
    import junit.framework.*;
    Q都是可以运行的。关于Junitq行的问题很有意思,下面单独说明?BR>  上面释概念“测试基(fixture)”,引入了两个对两个Ҏ(gu)的测试。命令模式与集成模式的本质区别是Q前者一ơ只q行一个测试?BR>
  • 集成模式
      利用TestSuite可以一个TestCase子类中所有test***()Ҏ(gu)包含q来一赯行,q可TestSuite子类也包含进来,从而行成了一U等U关pR可以把TestSuite视ؓ一个容器,可以盛放TestCase中的test***()Ҏ(gu)Q它自己也可以嵌套。这U体pL构,非常cM于现实中E序一步步开发一步步集成的现c?BR>  对上面的例子Q有代码如下Q?
    public class MoneyTest extends TestCase {//TestCase的子c?BR>    ....
        public static Test suite() {//静态Test
            TestSuite suite= new TestSuite();//生成一个TestSuite
            suite.addTest(new MoneyTest("testEquals")); //加入试Ҏ(gu)
            suite.addTest(new MoneyTest("testSimpleAdd"));
            return suite;
        }
    }

      从Junit2.0开始,有列L(fng)Ҏ(gu):
    public class MoneyTest extends TestCase {//TestCase的子c?BR>    ....
        public static Test suite() {静态Test
            return new TestSuite(MoneyTest.class); //以类为参?/INS>
        }
    }

      TestSuite见嵌套的例子Q在后面应用案例中有?BR>  

4、测试代码的q行
  先说最常用的集成模式?BR>  试代码写好以后Q可以相应的cM写mainҎ(gu)Q用java命o直接q行Q也可以不写mainҎ(gu)Q用Junit提供的运行器q行。Junit提供了textui,awtui和swingui三种q行器?BR>  以前面第2步中的AllTestsq行ZQ可有四U:

java junit.textui.TestRunner junit.samples.AllTests
java junit.awtui.TestRunner junit.samples.AllTests
java junit.swingui.TestRunner junit.samples.AllTests
java junit.samples.AllTests

  mainҎ(gu)中一般也都是单地用Runner调用suite()Q当没有mainӞTestRunner自己以运行的cMؓ参数生成了一个TestSuite.
  
  对于命o模式的运行,有两U方法?BR>
  • 静态方?BR>
    TestCase test= new MoneyTest("simple add") {
    public void runTest() {
    testSimpleAdd();
    }
    };

  • 动态方?BR>
    TestCase test= new MoneyTest("testSimpleAdd");

  我试了一下,好象有问题,哪位朋友成功了,hҎ(gu)一下?/DEL>实可以?BR>
import junit.framework.*;

public class MoneyTest extends TestCase {//TestCase的子c?/INS>
    private Money f12CHF;//提取公用的对?/INS>
    private Money f14CHF;   
    public MoneyTest(String name){
        super(name);
    }
    protected void setUp() {//初始化公用对?/INS>
        f12CHF= new Money(12, "CHF");
        f14CHF= new Money(14, "CHF");
    }
    public void testEquals() {//试equalsҎ(gu)的正?BR>        Assert.assertTrue(!f12CHF.equals(null));
        Assert.assertEquals(f12CHF, f12CHF);
        Assert.assertEquals(f12CHF, new Money(12, "CHF"));
        Assert.assertTrue(!f12CHF.equals(f14CHF));
    }
    
    public void testAdd() {//试addҎ(gu)的正?BR>        Money expected= new Money(26, "CHF");
        Money result= f12CHF.add(f14CHF);
        Assert.assertTrue(expected.equals(result));
    }
//    public static void main(String[] args) {
//        TestCase test=new MoneyTest("simple add") {
//                public void runTest() {
//                    testAdd();
//                }
//            };
//        junit.textui.TestRunner.run(test);
//    }
    public static void main(String[] args) {
        TestCase test=new MoneyTest("testAdd");
        junit.textui.TestRunner.run(test);
    }
}


再给一个静态方法用集成试的例子:
public static Test suite() {
    TestSuite suite= new TestSuite();
    suite.addTest(
        new testCar("getWheels") {
            protected void runTest() { testGetWheels(); }
        }
    );

    suite.addTest(
        new testCar("getSeats") {
            protected void runTest() { testGetSeats(); }
        }
    );
    return suite;
}

5、应用案?/STRONG>

  1. Junit Primer例程Q运行如下:
    java com.hedong.JunitLearning.Primer.ShoppingCartTest

  2. Ant+Junit+Mailto实现自动~译、调试ƈ发送结果的build.xml
  3. JUnit实施,写得很棒Q理解也深刻。例E运行如下:
    java com.hedong.JunitLearning.car.testCarNoJunit
    java junit.swingui.TestRunner com.hedong.JunitLearning.car.testCar

  4. Junit与log4jl合Q阿菜的例程q行Q?
    cd acai
    ant junit






6、一些问?/STRONG>
  有h在实践基上ȝZ些非常有价值的使用技巧,我没有经q一一“测试”,暂列在此?BR>
  1. 不要用TestCase的构造函数初始化FixtureQ而要用setUp()和tearDown()Ҏ(gu)?BR>
  2. 不要依赖或假定测试运行的序Q因为JUnit利用Vector保存?gu)试?gu)。所以不同的q_会按不同的顺序从Vector中取出测试方法?INS>不知3.8中是不是q是如此Q不q它提供的例子有一个是指定用VectorSuite的,如果不指定呢Q?/INS>
  3. 避免~写有副作用的TestCase。例如:如果随后的测试依赖于某些特定的交易数据,׃要提交交易数据。简单的回滚可以了?BR>
  4. 当承一个测试类Ӟ记得调用父类的setUp()和tearDown()Ҏ(gu)?BR>
  5. 测试代码和工作代码攑֜一P一边同步编译和更新。(使用Ant中有支持junit的task.Q?BR>
  6. 试cd试Ҏ(gu)应该有一致的命名Ҏ(gu)。如在工作类名前加上test从而Ş成测试类名?BR>
  7. 保试与时间无养I不要依赖使用q期的数据进行测试。导致在随后的维护过E中很难重现试?BR>
  8. 如果你编写的软g面向国际市场Q编写测试时要考虑国际化的因素。不要仅用母语的Localeq行试?BR>
  9. 可能地利用JUnit提供地assert/failҎ(gu)以及异常处理的方法,可以使代码更为简z?BR>
  10. 试要尽可能地小Q执行速度快?BR>
  11. 把测试程序徏立在与被对象相同的包中
  12. 在你的原始代码目录中避免试码出玎ͼ可在一个源码镜像目录中放测试码
  13. 在自q应用E序包中包含一个TestSuite试c?BR>



7、相兌源下?/STRONG>
以下jar包,我只是做了打包、编译和调试的工作,供下载学?fn)之用,相关的权利属于原作者?BR>
  1. 可运行例E?jar
  2. Build.xml
  3. 阿菜的例E?/A>
  4. Junit API 汉译(pdf)

8、未完成的Q?/STRONG>

  1. httpunit
  2. cactus
  3. Junit用链接池试

主要参考文献:

  1. JUnit入門
    http://www.dotspace.twmail.org/Test/JUnit_Primer.htm
  2. 怎样使用Junit Frameworkq行单元试的编?BR>http://www.chinaunix.net/bbsjh/14/546.html
  3. Ant+Junit+Log4J+CVSq行XP模式开发的建立
    http://ejb.cn/modules/tutorials/printpage.php?tid=4
  4. 用HttpUnit试Web应用E序
    http://www.zdnet.com.cn/developer/code/story/0,2000081534,39033726,00.htm
  5. 有没有用qCactus的,W(xu)eb层的试是Cactusq是JUnitQ?BR>http://www.jdon.com/jive/thread.jsp?forum=16&thread=9156
  6. Ant+junit的测试自动化 biggieQ原作)
    http://www.csdn.net/Develop/article/19%5C19748.shtm
  7. JUnit实施
    http://www.neweasier.com/article/2002-08-07/1028723459.html
  8. JUnitTest Infected: Programmers Love Writing Tests
    http://junit.sourceforge.net/doc/testinfected/testing.htm
  9. JUnit Cookbook
    http://junit.sourceforge.net/doc/cookbook/cookbook.htm
  10. JUnit Primer
    http://www.itu.dk/~lthorup/JUnitPrimer.html
  11. IBM DevelopWorks
    http://www-106.ibm.com/search/searchResults.jsp?query=junit&searchScope=dW&searchType=1&searchSite=dWChina&pageLang=zh&langEncoding=gb2312&Search.x=0&Search.y=0&Search=Search


]]>
junit使用明手? http://m.tkk7.com/jackybu/articles/2897.html?/dc:creator>?/author>Thu, 07 Apr 2005 02:43:00 GMThttp://m.tkk7.com/jackybu/articles/2897.htmlhttp://m.tkk7.com/jackybu/comments/2897.htmlhttp://m.tkk7.com/jackybu/articles/2897.html#Feedback0http://m.tkk7.com/jackybu/comments/commentRss/2897.htmlhttp://m.tkk7.com/jackybu/services/trackbacks/2897.html
使用目的
      junit是java中书写unit test的frameworkQ目前一些流行的unit test工具大都都是在junit上扩展而来的。目前它的版本是junit3.8.1Q可以从www.junit.org上下载?BR>
用法
1.       基本使用步骤QJunit的用非常简单,它的基本使用步骤Q?BR>
-          创徏Q从junit.framework.TestCasezunit test需要的test case

-          书写试Ҏ(gu)Q提供类g如下函数{֐的测试方法:

public void testXXXXX();

-          ~译Q书写完test case后,~译所写的test casec?BR>
-          q行Q启动junit test runnerQ来q行q个test case?BR>
Junit提供?个基本的test runnerQ字W界面和囑Ş界面。启动命令分别如下:

a 囑Ş界面Q?BR>
java junit.swingui.TestRunner XXXXX

b 字符界面Q?BR>
java junit.textui.TestRunner XXXXX

2.       使用例子Q?BR>
import junit.frmework.TestCase;

public class TestSample extends TestCaset{

       public void testMethod1(){

              assertTrue( true);

}

}

3.       setUp与tearDownQ这两个函数是junit framework中提供初始化和反初始化每个测试方法的。setUp在每个测试方法调用前被调用,负责初始化测试方法所需要的试环境QtearDown在每个测试方法被调用之后被调用,负责撤销试环境。它们与试Ҏ(gu)的关pd以描q如下:



    试开?-> setUp -> testXXXX -> tearDown ->试l束




4.       使用例子Q?BR>
import junit.frmework.TestCase;

public class TestSample extends TestCaset{

       protected void setUp(){

              //初始化…?BR>
}



       public void testMethod1(){

              assertTrue( true);

}



potected void tearDown(){

      //撤销初始化…?BR>
}

}

5.       区分fail、exception?BR>
-          failQ期望出现的错误。生原因:assert函数出错Q如assertFalse(true)Q;fail函数产生Q如fail(…?Q?BR>
-          exceptionQ不期望出现的错误,属于unit testE序q行时抛出的异常。它和普通代码运行过E中抛出的runtime异常属于一U类型?BR>
对于assert、fail{函数请参见junit的javadoc?BR>
6.       使用例子Q?BR>
import junit.frmework.TestCase;

public class TestSample extends TestCaset{

       protected void setUp(){

              //初始化…?BR>
}



       public void testMethod1(){

              …?BR>
              try{

                     boolean b= …?BR>
                     assertTrue( b);

                     throw new Exception( “This is a test.?;

                     fail( “Unable point.?;     //不可能到?BR>
              }catch(Exception e){

                     fail( “Yes, I catch u?; //应该到达?BR>
}

…?BR>
}



potected void tearDown(){

      //撤销初始化…?BR>
}

}

7.       l装TestSuiteQ运行更多的test。在junit中,Test、TestCase和TestSuite三者组成了composiste pattern。通过l装自己的TestSuiteQ可以完成对d到这个TestSuite中的所有的TestCase的调用。而且q些定义的TestSuiteq可以组装成更大的TestSuiteQ这样同时也方便了对于不断增加的TestCase的管理和l护?BR>
      它的另一个好处就是,可以从这个TestCase?wi)的L一个节点(TestSuite或TestCaseQ开始调用,来完成这个节点以下的所有TestCase的调用。提高了unit test的灵zL?BR>
8.       使用例子Q?BR>
import junit.framework.Test;

import junit.framework.TestSuite;

public class TestAll{

public class TestAll{

       //定义一个suiteQ对于junit的作用可以视为类gjava应用E序的main?BR>
   public static Test suite(){

       TestSuite suite = new TestSuite("Running all tests.");

       suite.addTestSuite( TestCase1.class);

       suite.addTestSuite( TestCase2.class);

       return suite;

   }

}

q行同运行单独的一个TestCase是一L(fng)Q参见step 1 “运行”?BR>
9.       使用Ant junit task。我们除了用java来直接运行junit之外Q我们还可以使用junit提供的junit task与antl合来运行。涉及的几个主要的ant task如下Q?BR>
-          <junit>Q定义一个junit task

-          <batchtest>Q位?lt;junit>中,q行多个TestCase

-          <test>Q位?lt;junit>中,q行单个TestCase

-          <formatter>Q位?lt;junit>中,定义一个测试结果输出格?BR>
-          <junitreport>Q定义一个junitreport task

-          <report>Q位?lt;junitreport>中,输出一个junit report

具体的语法请参见相关文档?BR>
10.   使用例子Q?BR>
<junit printsummary="yes" haltonfailure="no">

   <classpath>

       <path refid="classpath"/>

       <pathelement location="${dist.junit}"/>

   </classpath>

   

   <formatter type="brief" usefile="false"/>

   <formatter type="xml"/>



   <batchtest todir="${doc.junitReport}">

       <fileset dir="${dist.junit}" includes="**/*Test.class" />

   </batchtest>

</junit>



<junitreport todir="${doc.junitReport}">

   <fileset dir="${doc.junitReport}">

       <include name="TEST*-*.xml"/>

   </fileset>

   <report format="frames" styledir="${junit.styleDir}" todir="${doc.junitReport}"/>

</junitreport>

查表
      junit的用ƈ不很难,然而要书写一个好的TestCase却ƈ非易事。一个不好的TestCase往往是既费了时_也v不了实际的作用。相反,一个好的TestCaseQ不仅可以很好的指出代码中存在的问题Q而且也可以作Z码更准确的文档,同时q在持箋集成的过E中起非帔R要的作用。在此给Z写TestCase旉要注意的几点Q?BR>
-          试的独立性:一ơ只试一个对象,方便定位出错的位|。这?层意思:一个TestCaseQ只试一个对象;一个TestMethodQ只试q个对象中的一个方法?BR>
-          l测试方法一个合适的名字?BR>
-          在assert函数中给出失败的原因Q如QassertTrue( “?should be true?  …?Q方便查错。在q个例子中,如果无法通过assertTrueQ那么给出的消息被昄。在junit中每个assert函数都有W一个参数是出错时显C消息的函数原型?BR>
-          试所有可能引起失败的地方Q如Q一个类中频J改动的函数。对于那些仅仅只含有getter/setter的类Q如果是由IDEQ如EclipseQ生的Q则可不;如果是h工写Q那么最好测试一下?BR>
-          在setUp和tearDown中的代码不应该是与测试方法相关的Q而应该是全局相关的。如针对与测试方法A和BQ在setUp和tearDown中的代码应该是A和B都需要的代码?BR>
-          试代码的组l:相同的包Q不同的目录。这P试代码可以讉K被测试类的protected变量/Ҏ(gu)Q方便测试代码的~写。放在不同的目录Q则方便了测试代码的理以及代码的打包和发布。一个例子如下:

src   <=源代码根目录

-com

    -mod1

        -class1

junit   <=试代码根目?BR>
-com

    -mod1

        -class1


]]>
[软g试]JUnit和单元测试入门简?/title><link>http://m.tkk7.com/jackybu/articles/2896.html</link><dc:creator>?/dc:creator><author>?/author><pubDate>Thu, 07 Apr 2005 02:42:00 GMT</pubDate><guid>http://m.tkk7.com/jackybu/articles/2896.html</guid><wfw:comment>http://m.tkk7.com/jackybu/comments/2896.html</wfw:comment><comments>http://m.tkk7.com/jackybu/articles/2896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/jackybu/comments/commentRss/2896.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/jackybu/services/trackbacks/2896.html</trackback:ping><description><![CDATA[1、几个相关的概念 <BR><BR>白盒试——把试对象看作一个打开的盒子,E序内部的逻辑l构和其他信息对试人员是公开的?<BR><BR>回归试——Y件或环境的修复或更正后的“再试”,自动试工具对这cL试尤其有用?<BR><BR>单元试——是最粒度的试Q以试某个功能或代码块。一般由E序员来做,因ؓ它需要知道内部程序设计和~码的细节?<BR><BR>JUnit ——是一个开发源代码的Java试框架Q用于编写和q行可重复的试。他是用于单元测试框架体pxUnit的一个实例(用于java语言Q。主要用于白盒测试,回归试?<BR><BR><BR><BR>2、单元测试概q?<BR><BR>2.1、单元测试的好处 <BR><BR>A、提高开发速度——测试是以自动化方式执行的,提升了测试代码的执行效率?<BR><BR>B、提高Y件代码质量——它使用版本发布至集成Q便于实Ch员除错。同时引入重构概念,让代码更q净和富有弹性?<BR><BR>C、提升系l的可信赖度——它是回归测试的一U。支持修复或更正后的“再试”,可确保代码的正确性?<BR><BR>2Q?、单元测试的针对对象 <BR><BR>A、面向过E的软g开发针对过E?<BR><BR>B、面向对象的软g开发针对对象?<BR><BR>C、可以做cL试,功能试Q接口测试(最常用于测试类中的Ҏ(gu)Q?<BR><BR>2.3、单元测试工具和框架 <BR><BR>目前的最行的单元测试工hxUnitpd框架Q常用的Ҏ(gu)语言不同分ؓJUnitQjavaQ,CppUnitQC++Q,DUnit QDelphi Q,NUnitQ?netQ,PhpUnitQPhp Q等{。该试框架的第一个和最杰出的应用就是由Erich Gamma Q《设计模式》的作者)和Kent BeckQXPQExtreme ProgrammingQ的创始?Q提供的开放源代码的JUnit?<BR><BR><BR><BR>3.Junit入门?<BR><BR>3.1、JUnit的好处和JUnit单元试~写原则 <BR><BR>好处Q?<BR><BR>A、可以ɋ试代码与品代码分开?<BR><BR>B、针Ҏ(gu)一个类的测试代码通过较少的改动便可以应用于另一个类的测试?<BR><BR>C、易于集成到试人员的构E中QJUnit和Ant的结合可以实施增量开发?<BR><BR>D、JUnit是公开源代码的Q可以进行二ơ开发?<BR><BR>C、可以方便地对JUnitq行扩展?<BR><BR>~写原则Q?<BR><BR>A、是化测试的~写Q这U简化包括测试框架的学习(fn)和实际测试单元的~写?<BR><BR>B、是使测试单元保持持久性?<BR><BR>C、是可以利用既有的测试来~写相关的测试?<BR><BR>3.2、JUnit的特?<BR><BR>A、用断aҎ(gu)判断期望值和实际值差异,q回Boolean倹{?<BR><BR>B、测试驱动设备用共同的初始化变量或者实例?<BR><BR>C、测试包l构便于l织和集成运行?<BR><BR>D、支持图型交互模式和文本交互模式?<BR><BR>3.3、JUnit框架l成 <BR><BR>A、对试目标q行试的方法与q程集合Q可UCؓ试用例(TestCase)?<BR><BR>B、测试用例的集合Q可容纳多个试用例(TestCase)Q将其称作测试包(TestSuite)?<BR><BR>C、测试结果的描述与记录?TestResult) ?<BR><BR>D、测试过E中的事件监听?TestListener)?<BR><BR>E、每一个测试方法所发生的与预期不一致状늚描述Q称其测试失败元?TestFailure) <BR><BR>F、JUnit Framework中的出错异常QAssertionFailedErrorQ?<BR><BR>JUnit框架是一个典型的Composite模式QTestSuite可以容纳Mz自Test的对象;当调用TestSuite对象的run()Ҏ(gu)是,会遍历自己容U的对象Q逐个调用它们的run()Ҏ(gu)。(可参考《程序员?003-6期)?<BR><BR>3.4、JUnit的安装和配置 <BR><BR>JUnit安装步骤分解Q?<BR><BR>在http://download.sourceforge.net/junit/中下载JUnit包ƈJunit压羃包解压到一个物理目录中Q例如CQ\Junit3.8.1Q?<BR>记录Junit.jar文g所在目录名Q例如CQ\Junit3.8.1\Junit.jarQ?<BR>q入操作pȝQ以Windows2000操作pȝ为准Q,按照ơ序点击“开始 讄 控制面板”?<BR>在控刉杉K项中选择“系l”,点击“环境变量”,在“系l变量”的“变量”列表框中选择“CLASS-PATH”关键字Q不区分大小写)Q如果该关键字不存在则添加?<BR>双击“CLASS-PATH”关键字d字符东yC:QJunit3.8.1\Junti.jar?注意Q如果已有别的字W串请在该字W串的字W结֊上分号“;?Q这L(fng)定修改后Junit可以在集成环境中应用了?<BR>对于IDE环境Q对于需要用到的JUnit的项目增加到l(f)ib中,其设|不同的IDE有不同的讄 ?<BR>3.5、JUnit中常用的接口和类 <BR><BR>Test接口——运行测试和攉试l果 <BR><BR>Test接口使用了Composite设计模式Q是单独试用例 QTestCaseQ,聚合试模式QTestSuiteQ及试扩展QTestDecoratorQ的共同接口?<BR>它的public int countTestCasesQ)Ҏ(gu)Q它来统计这ơ测试有多少个TestCaseQ另外一个方法就是public void runQ?TestResult Q,TestResult是实例接受测试结果, runҎ(gu)执行本次试?<BR>TestCase抽象cZ—定义测试中固定Ҏ(gu) <BR><BR>TestCase是Test接口的抽象实玎ͼQ不能被实例化,只能被承)其构造函数TestCase(string name)Ҏ(gu)输入的测试名Uname创徏一个测试实例。由于每一个TestCase在创建时都要有一个名Uͼ若某试p|了,便可识别出是哪个试p|?<BR>TestCasecM包含的setUp()、tearDown()Ҏ(gu)。setUp()Ҏ(gu)集中初始化测试所需的所有变量和实例Qƈ且在依次调用试cM的每个测试方法之前再ơ执行setUp()Ҏ(gu)。tearDown()Ҏ(gu)则是在每个测试方法之后,释放试E序Ҏ(gu)中引用的变量和实例?<BR>开发h员编写测试用例时Q只需l承TestCaseQ来完成runҎ(gu)卛_Q然后JUnit获得试用例Q执行它的runҎ(gu)Q把试l果记录在TestResult之中?<BR>Assert静态类——一pd断言Ҏ(gu)的集?<BR><BR>Assert包含了一l静态的试Ҏ(gu)Q用于期望值和实际值比Ҏ(gu)否正,x试失败,Assertcd会抛Z个AssertionFailedError异常QJUnit试框架这U错误归入Failesq加以记录,同时标志为未通过试。如果该cL法中指定一个Stringcd的传参则该参数将被做为AssertionFailedError异常的标识信息,告诉试人员改异常的详细信息?<BR>JUnit 提供?大类31l断aҎ(gu)Q包括基断言、数字断a、字W断a、布?yu)(dng)断a、对象断a?<BR>其中assertEqualsQObject expcted,Object actual)内部逻辑判断使用equals()Ҏ(gu)Q这表明断言两个实例的内部哈希值是否相{时Q最好用该Ҏ(gu)对相应类实例的D行比较。而assertSameQObject expected,Object actualQ内部逻辑判断使用了Javaq算W?=”,q表明该断言判断两个实例是否来自于同一个引用(ReferenceQ,最好用该Ҏ(gu)对不同类的实例的D行比寏VasserEquals(String message,String expected,String actual)该方法对两个字符串进行逻辑比对Q如果不匚w则显C着两个字符串有差异的地斏VComparisonFailurecL供两个字W串的比对,不匹配则l出详细的差异字W?<BR>TestSuite试包类——多个测试的l合 <BR><BR>TestSuitec负责组装多个Test Cases。待得cM可能包括了对被测cȝ多个试Q而TestSuit负责攉q些试Q我们可以在一个测试中Q完成全部的对被类的多个测试?<BR>TestSuitecdCTest接口Q且可以包含其它的TestSuites。它可以处理加入Test时的所有抛出的异常?<BR>TestSuite处理试用例?个规U(否则会被拒绝执行试Q?<BR>A 试用例必须是公有类QPublicQ?<BR><BR>B 试用例必须l承与TestCasec?<BR><BR>C 试用例的测试方法必L公有的( Public Q?<BR><BR>D 试用例的测试方法必被声明为Void <BR><BR>E 试用例中测试方法的前置名词必须是test <BR><BR>F 试用例中测试方法误M传递参?<BR><BR>n TestResultl果cd其它cM接口 <BR><BR>TestResultl果c集合了L试累加l果Q通过TestResult实例传递个每个试的RunQ)Ҏ(gu)。TestResult在执行TestCase是如果失败会异常抛出 <BR>TestListener接口是个事g监听规约Q可供TestRunnercM用。它通知listener的对象相关事ӞҎ(gu)包括试开始startTest(Test test)Q测试结束endTest(Test test),错误Q增加异常addError(Test test,Throwable t)和增加失败addFailure(Test test,AssertionFailedError t) <BR>TestFailurep|cL个“失败”状늚攉c,解释每次试执行q程中出现的异常情况。其toString()Ҏ(gu)q回“失败”状늚要描q?<BR><BR><BR>3.6、JUnit一个实?<BR><BR>在控制台中简单的范例如下Q?<BR>1、写个待试的Trianglec,创徏一个TestCase的子cExampleTest: <BR>2?ExampleTest中写一个或多个试Ҏ(gu)Q断a期望的结?注意Q以test作ؓ待测试的Ҏ(gu)的开_q样q些Ҏ(gu)可以被自动找到ƈ被测? <BR>3?ExampleTest中写一个suite()Ҏ(gu)Q它会用反动态的创徏一个包含所有的testXxxxҎ(gu)的测试套Ӟ <BR>4?ExampleTest可以写setUp()、tearDown()Ҏ(gu)Q以便于在测试时初始化或销毁测试所需的所有变量和实例。(不是必须的) <BR><BR>5、写一个main()Ҏ(gu)以文本运行器或其它GUI的方式方便的q行试 <BR><BR>6、编译ExampleTestQ执行测试?<BR><BR>3.7、Eclipse中JUnit的?<BR><BR>Eclipse自带了一个JUnit的插Ӟ不用安装可以在你的目中开始测试相关的c,q且可以调试你的试用例和被试cR?<BR><BR>使用步骤如下Q?<BR><BR>1、新Z个测试用例,点击“File->New->Other…菜单项Q在弹出的“New”对话框中选择”Java->JUnit?下的TestCase 或TestSuiteQ就q入“New JUnit TestCase”对话框 <BR><BR>2、在“New JUnit TestCase”对话框填写相应的栏目,主要有NameQ测试用例名Q,SuperClassQ测试的类一般是默认的junit.framework.TestCaseQ,Class Under TestQ被试的类Q,Source FolderQ测试用例保存的目录Q,PackageQ测试用例包名)Q及是否自动生成main,setUp,tearDownҎ(gu)?<BR><BR>3、如果点M面的”Next>”按钮,你还可以直接N你x试的被测试类的方法,Eclipse自动生成与被选方法相应的试Ҏ(gu)Q点几ZFishish”按钮后一个测试用例就创徏好了?<BR><BR>4、编写完成你的测试用例后Q点几ZRun”按钮就可以看到q行l果了?<BR><BR>3.8、JUnit的扩展应?<BR><BR>以下|列了些JUnit的扩展应用: <BR><BR>JUnit + HttpUnit=WEB功能试工具 <BR>JUnit + hansel =代码覆盖试工具 <BR>JUnit + abbot =界面自动回放试工具 <BR>JUnit + dbunit =数据库测试工?<BR>JUnit + junitperf=性能试工具 <BR><BR>3.9、一些用JUnitl验 <BR><BR>不要用TestCase的构造函数初始化Q而要用setUp()和tearDown()Ҏ(gu)?<BR>不要依赖或假定测试运行的序Q因为JUnit利用Vector保存?gu)试?gu)。所以不同的q_会按不同的顺序从Vector中取出测试方法?<BR>避免~写有副作用的TestCase。例如:如果随后的测试依赖于某些特定的交易数据,׃要提交交易数据。简单的回滚可以了?<BR>当承一个测试类Ӟ记得调用父类的setUp()和tearDown()Ҏ(gu)?<BR>测试代码和工作代码攑֜一P一边同步编译和更新?<BR>试cd试Ҏ(gu)应该有一致的命名Ҏ(gu)。如在工作类名前加上test从而Ş成测试类名?<BR>保试与时间无养I不要依赖使用q期的数据进行测试。导致在随后的维护过E中很难重现试?<BR>如果你编写的软g面向国际市场Q编写测试时要考虑国际化的因素。不要仅用母语的Localeq行试?<BR>可能地利用JUnit提供地assert/failҎ(gu)以及异常处理的方法,可以使代码更为简z?<BR>试要尽可能地小Q执行速度快?<BR><BR><BR>参考资料与附g <BR><BR>1. http:// www.junit.org JUnit官方|站 <BR><BR>2. http://bbs.51cmm.com 的测试论?<BR><BR>3. http://www.uml.org.cn 的Y件测试专?<BR><BR>4. 单元试 《程序员?2002q??<BR><BR>5. JUnit设计模式分析 《程序员?003q??<BR><BR>6. 《Y件测试和JUnit实践?<BR><BR>7. 附gTriangle.java 一个要试的类 <BR><BR>8. 附gExampleTest.java 一个测试用例类 <BR><BR><BR><BR><BR><BR>Triangle.java <BR><BR>/** <BR><BR>* this is Triangle class <BR><BR>* @author liujun <BR><BR>*/ <BR><BR>public class Triangle <BR><BR>{ <BR><BR>//定义三角形的三边 <BR><BR>protected long lborderA = 0; <BR><BR>protected long lborderB = 0; <BR><BR>protected long lborderC = 0; <BR><BR><BR><BR>//构造函?<BR><BR>public Triangle(long lborderA,long lborderB,long lborderC) <BR><BR>{ <BR><BR>this.lborderA = lborderA; <BR><BR>this.lborderB = lborderB; <BR><BR>this.lborderC = lborderC; <BR><BR>} <BR><BR>/** <BR><BR>* 判断是否是三角Ş <BR><BR>* 是返回tureQ不是返回false <BR><BR>*/ <BR><BR>public boolean isTriangle(Triangle triangle) <BR><BR>{ <BR><BR>boolean isTrue = false; <BR><BR>//判断边界Q大?于200Q出界返回false <BR><BR>if((triangle.lborderA>0&&triangle.lborderA<200) <BR><BR>&&(triangle.lborderB>0&&triangle.lborderB<200) <BR><BR>&&(triangle.lborderC>0&&triangle.lborderC<200)) <BR><BR>{ <BR><BR>//判断两边之和大于W三?<BR><BR>if((triangle.lborderA<(triangle.lborderB+triangle.lborderC)) <BR><BR>&&(triangle.lborderB<(triangle.lborderA+triangle.lborderC)) <BR><BR>&&(triangle.lborderC<(triangle.lborderA+triangle.lborderB))) <BR><BR>isTrue = true; <BR><BR>} <BR><BR>return isTrue; <BR><BR>} <BR><BR><BR><BR>/** <BR><BR>* 判断三角形类?<BR><BR>* {腰三角形返回字W串“等C角Ş”; <BR><BR>* {边三角形返回字W串“等边三角Ş”; <BR><BR>* 其它三角形返回字W串“不{边三角形”; <BR><BR>*/ <BR><BR>public String isType(Triangle triangle) <BR><BR>{ <BR><BR>String strType = ""; <BR><BR>// 判断是否是三角Ş <BR><BR>if(this.isTriangle(triangle)) <BR><BR>{ <BR><BR>//判断是否是等边三角Ş if(triangle.lborderA==triangle.lborderB&&triangle.lborderB==triangle.lborderC) <BR><BR>strType = "{边三角?; <BR><BR>//判断是否是不{边三角?<BR><BR>else if((triangle.lborderA!=triangle.lborderB)&& <BR><BR>(triangle.lborderB!=triangle.lborderC)&& <BR><BR>(triangle.lborderA!=triangle.lborderC)) <BR><BR>strType = "不等边三角Ş"; <BR><BR>else <BR><BR>strType="{腰三角?; <BR><BR>} <BR><BR>return strType; <BR><BR>} <BR><BR>} <BR><BR><BR><BR>ExampleTest.java <BR><BR>import junit.framework.*; <BR><BR>/** <BR><BR>* Some tests. <BR><BR>* <BR><BR>*/ <BR><BR>public class ExampleTest extends TestCase { <BR><BR>public Triangle triangle; <BR><BR>//初始?<BR><BR>protected void setUp() { <BR><BR>triangle=new Triangle(10,2,9); <BR><BR>} <BR><BR><BR><BR>public static Test suite() { <BR><BR>return new TestSuite(ExampleTest.class); <BR><BR>} <BR><BR>//函数isTriangle()的测试用?<BR><BR>public void testIsTriangle() { <BR><BR>assertTrue(triangle.isTriangle(triangle)); <BR><BR>} <BR><BR>//函数isType()的测试用?<BR><BR>public void testIsType() <BR><BR>{ <BR><BR>assertEquals("q次试",triangle.isType(triangle),"不等边三角Ş"); <BR><BR>} <BR><BR><BR><BR>//执行试 <BR><BR>public static void main (String[] args) { <BR><BR>//文本方式 <BR><BR>junit.textui.TestRunner.run(suite()); <BR><BR>//Swingui方式 <BR><BR>//junit.swingui.TestRunner.run(suite().getClass()); <BR><BR>//awtui方式 <BR><BR>//junit.awtui.TestRunner.run(suite().getClass()); <BR><BR><BR><BR>} <BR><BR>}<img src ="http://m.tkk7.com/jackybu/aggbug/2896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/jackybu/" target="_blank">?/a> 2005-04-07 10:42 <a href="http://m.tkk7.com/jackybu/articles/2896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://m.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://www-774220.com" target="_blank">sssۺþþþ</a>| <a href="http://89kino.com" target="_blank">Ƶ</a>| <a href="http://www19977.com" target="_blank">jjzzŮ</a>| <a href="http://323c.com" target="_blank">һ</a>| <a href="http://jj5c.com" target="_blank">պһ</a>| <a href="http://chaoxung.com" target="_blank">ҹƵ</a>| <a href="http://wwwdf221.com" target="_blank">18ŮˮѸëƬ</a>| <a href="http://18yinren.com" target="_blank">..ŷһ</a>| <a href="http://3333kkkk.com" target="_blank">޾Ʒ</a>| <a href="http://sjzbosite.com" target="_blank">Ů18ëƬˮѲ</a>| <a href="http://cztbm.com" target="_blank">aëƬѹۿ</a>| <a href="http://wlamyx.com" target="_blank">ɫ͵͵ۺav78</a>| <a href="http://xjkakatong.com" target="_blank">޹Ʒ˾þ</a>| <a href="http://1000hu.com" target="_blank">Ʒѹۿþþ</a>| <a href="http://wwwkk5679.com" target="_blank">þþƵ</a>| <a href="http://9844555.com" target="_blank">Ʒһ</a>| <a href="http://33338x.com" target="_blank">Aһ</a>| <a href="http://xtolm.com" target="_blank">ѹƷƵ</a>| <a href="http://aqddv.com" target="_blank">һëƬ</a>| <a href="http://jybelt.com" target="_blank">aëƬƵ</a>| <a href="http://kingleadsw.com" target="_blank">avƬ߹ۿ</a>| <a href="http://cxljdz.com" target="_blank">޸Ƶվ</a>| <a href="http://0515bh.com" target="_blank">˳77777ɫ</a>| <a href="http://jcmy5188.com" target="_blank">ĻӰѹۿַ</a>| <a href="http://gzbaida.com" target="_blank">18վƬѹۿ</a>| <a href="http://mm9d.com" target="_blank">Ƶһ</a>| <a href="http://youtobey.com" target="_blank">ɫ͵͵ۺav78</a>| <a href="http://zbvip888.com" target="_blank">޻ɫվ</a>| <a href="http://xxxxcccc.com" target="_blank">޾Ʒmv߹ۿվ </a>| <a href="http://hljjlhl.com" target="_blank">Ƶ߹ۿӰԺ</a>| <a href="http://14743592.com" target="_blank">Ůҹ24ʽƵ</a>| <a href="http://binz132.com" target="_blank">һëƬ**ѿԿ20</a>| <a href="http://bentuxinli.com" target="_blank">˾þۺӰԺҳ</a>| <a href="http://imfever.com" target="_blank">ƷAһ</a>| <a href="http://haichuanwangluo.com" target="_blank">޹ƷAVþۺӰԺ</a>| <a href="http://www-091w.com" target="_blank">ձ2019߹ۿ</a>| <a href="http://adcbgy.com" target="_blank">ŷ޾Ʒ99ëƬѸۿ</a>| <a href="http://hbjpxnyqckj.com" target="_blank">һձƵѹۿ </a>| <a href="http://kan63.com" target="_blank">һƵ</a>| <a href="http://cdkunyu.com" target="_blank">ɫվWWWĻ</a>| <a href="http://43sihu.com" target="_blank">ŷۺ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>