??xml version="1.0" encoding="utf-8" standalone="yes"?> L版本控制工具介绍 基本概念 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> 三?nbsp;q行试cR?BR> q行试成功?/P>
我们的单元测试这样就完成了吗?不,上面的测试只能算是一ơ验证而已。我们给的数据中Q最大?是数l的最后一个元素,如果9是第一个元素它q正吗Q如果数据是负数呢?{等。我们的求最大值函数有着很多的边界情况需要单元测试来验证?BR> 因此Q我们在写单元测试之前,一定要Ҏ(gu)试做一个周全的计划Q预先设|好要测试的内容Q可能发生错误的边界条g?BR>下面是对Largest做的试计划Q?BR>1?nbsp;数组元素的位|是否对最大g生媄响?
版本控制是程序开发、管理必不可的工具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>
现在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>
一?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比较器视图)
附录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>
]]>
一个比较最大值的函数
我们首先引入一个比较最大值的函数。我们传入一个类型ؓ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()来判断?对异常的情况又如何处理呢Qq验证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>
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/
]]>
试是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>
1、概q?/STRONG> 对不同性质的被对象,如ClassQJspQServletQEjb{,Junit有不同的使用技巧,以后慢慢地分别讲叙。以下以Class试Z讲解Q除非特D说明?/P>
2、下载安?/STRONG> 3、Junit架构 public Money(int amount, String currency) { public int amount() { public String currency() { Assert.assertTrue(!m12CHF.equals(null));//q行不同情况的测?/INS> protected void setUp() {//初始化公用对?/INS> 4、测试代码的q行 public class MoneyTest extends TestCase {//TestCase的子c?/INS> suite.addTest( 5、应用案?/STRONG> 8、未完成的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>
下面以Moneyq个cMؓ例进行说明?
private int fAmount;//余额
private String fCurrency;//货币cd
fAmount= amount;
fCurrency= currency;
}
return fAmount;
}
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">集成模式.
利用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 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 void testEquals() { //把测试代码放在testEquals?/INS>
Money m12CHF= new Money(12, "CHF"); //本行和下一行进行一些初始化
Money m14CHF= new Money(14, "CHF");
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清除。如下:
private Money f12CHF;//提取公用的对?/INS>
private Money f14CHF;
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ƈ在文仉行增?
利用TestSuite可以一个TestCase子类中所有test***()Ҏ(gu)包含q来一赯行,q可TestSuite子类也包含进来,从而行成了一U等U关pR可以把TestSuite视ؓ一个容器,可以盛放TestCase中的test***()Ҏ(gu)Q它自己也可以嵌套。这U体pL构,非常cM于现实中E序一步步开发一步步集成的现c?BR> 对上面的例子Q有代码如下Q?
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 static Test suite() {静态Test
return new TestSuite(MoneyTest.class); //以类为参?/INS>
}
}
TestSuite见嵌套的例子Q在后面应用案例中有?BR>
先说最常用的集成模式?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.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>
public void runTest() {
testSimpleAdd();
}
};
我试了一下,好象有问题,哪位朋友成功了,hҎ(gu)一下?/DEL>实可以?BR>
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);
}
}
再给一个静态方法用集成试的例子:
TestSuite suite= new TestSuite();
suite.addTest(
new testCar("getWheels") {
protected void runTest() { testGetWheels(); }
}
);
new testCar("getSeats") {
protected void runTest() { testGetSeats(); }
}
);
return suite;
}
java junit.swingui.TestRunner com.hedong.JunitLearning.car.testCar
ant junit
6、一些问?/STRONG>
有h在实践基上ȝZ些非常有价值的使用技巧,我没有经q一一“测试”,暂列在此?BR>
7、相兌源下?/STRONG>
以下jar包,我只是做了打包、编译和调试的工作,供下载学?fn)之用,相关的权利属于原作者?BR>
主要参考文献:
http://www.dotspace.twmail.org/Test/JUnit_Primer.htm
http://ejb.cn/modules/tutorials/printpage.php?tid=4
http://www.zdnet.com.cn/developer/code/story/0,2000081534,39033726,00.htm
http://www.csdn.net/Develop/article/19%5C19748.shtm
http://www.neweasier.com/article/2002-08-07/1028723459.html
http://junit.sourceforge.net/doc/testinfected/testing.htm
http://junit.sourceforge.net/doc/cookbook/cookbook.htm
http://www.itu.dk/~lthorup/JUnitPrimer.html
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
]]>