??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
试驱动开?Test Driven Development/TDD
试用例/TestCase/TC
设计/Design
重构/Refactoring
{TDD的目标}
Clean Code That Works
q句话的含义是,事实上我们只做两件事情:让代码奏效(WorkQ和让代码洁净QCleanQ,前者是把事情做对,后者是把事情做好。想想看Q其实我们^时所做的所有工作,除去无用的工作和错误的工作以外,真正正确的工作,q且是真正有意义的工作,其实也就只有两大c:增加功能和提升设计,而TDD正是在这个原则上产生的。如果?zhn)的工作ƈ非我们想象的q样Q(q意味着(zhn)还存在W三cL有意义的工作,或者?zhn)所要做的根本和我们在说的是两回事)Q那么这告诉我们(zhn)ƈ不需要TDDQ或者不适用TDD。而如果我们偶然猜对(q对于我来说是偶Ӟ而对于Kent Beck和Martin Fowlerq样的大师来说则是辛勤工作的成果Q,那么恭喜(zhn),TDD有可能成为?zhn)显著提升工作效率的一件法宝。请不要信疑Q若卌,因ؓM一Ҏ(gu)的技术——只要是从根本上改变人的行ؓ方式的技术——就必然使得怿它的来越怿Q不信的来越不信。这好比学游泳Q唯一能学会游泳的途径是亲自下去游,除此之外别无他法。这也好比成功学Q即使把卡耐基或希?dng)博士的书倒背如流也不能拥有积极的心态,可当你以U极的心态去成就了一番事业之后,你就再也M开它了。相信我QTDD也是q样Q想试用TDD的h们,请遵循下面的步骤Q?/p>
~写TestCase --> 实现TestCase --> 重构 Q确定范围和目标Q?/td> Q增加功能) Q提升设计)
[友情提示Q敏捷徏模中的一个相当重要的实践被称为:Prove it With CodeQ这U想法和TDD不谋而合。]
{TDD的优点}
『充满吸引力的优炏V?/b>
『不显而易见的优点?/b>
『有争议的优炏V?/b>
{TDD的步骤}
~写TestCase --> 实现TestCase --> 重构 Q不可运行) Q可q行Q?/td> Q重构)
步骤 | 制品 |
Q?Q快速新增一个测试用?/td> | 新的TestCase |
Q?Q编译所有代码,刚刚写的那个试很可能编译不通过 | 原始的TODO List |
Q?Q做可能少的改动,让编译通过 | Interface |
Q?Q运行所有的试Q发现最新的试不能~译通过 | Q?Red Bar) |
Q?Q做可能少的改动,让测试通过 | Implementation |
Q?Q运行所有的试Q保证每个都能通过 | Q?Green Bar) |
Q?Q重构代码,以消除重复设?/td> | Clean Code That Works |
{FAQ}
[什么时候重构?]
如果(zhn)在软g公司工作Q就意味着(zhn)成天都会和想通过重构改善代码质量的想法打交道Q不仅?zhn)如此Q?zhn)的大部分同事也都如此。可是,I竟什么时候该重构Q什么情况下应该重构呢?我相信?zhn)和(zhn)的同事可能有很多不同的看法,最常见的答案是“该重构旉构”,“写不下ȝ时候重构”,和“下一ơP代开始之前重构”,或者干脆就是“最q没旉Q就不重构了Q下ơ有旉的时候重构吧”。正如?zhn)已经预见到我惌的——这些想法都是对重构的误解。重构不是一U构Y件的工具Q不是一U设计Y件的模式Q也不是一个Y件开发过E中的环节,正确理解重构的h应该把重构看成一U书写代码的方式Q或习惯Q重构时时刻L可能发生。在TDD中,除去~写试用例和实现测试用例之外的所有工作都是重构,所以,没有重构M设计都不能实现。至于什么时候重构嘛Q还要分开看,有三句话是我的经验:实现试用例旉构代码,完成某个Ҏ(gu)时重构设计Q品的重构完成后还要记得重构一下测试用例哦?/p>
[什么时候设计?]
q个问题比前面一个要隑֛{的多,实话实说Q本人在依照TDD开发Y件的时候也常常被这个问题困扎ͼL觉得有些问题应该在写试用例之前定下来,而有些问题应该在新增一个一个测试用例的q程中自然出玎ͼ水到渠成。所以,我的是,设计的时机应该由开发者自己把握,不要受到TDD方式的限Ӟ但是Q不需要事先确定的事一定不能事先确定,免得捆住了自q手脚?/p>
[什么时候增加新的TestCaseQ]
没事做的时候。通常我们认ؓQ如果你要增加一个新的功能,那么先写一个不能通过的TestCaseQ如果你发现了一个bugQ那么先写一个不能通过的TestCaseQ如果你现在什么都没有Q从0开始,请先写一个不能通过的TestCase。所有的工作都是从一个TestCase开始。此外,q要注意的是Q一些大师要求我们每ơ只允许有一个TestCase亮红灯,在这个TestCase没有Green之前不可以写别的TestCaseQ这U要求可以适当考虑Q但即有多个TestCase亮红灯也不要紧,q未q反TDD的主要精?/p>
[TestCase该怎么写?]
试用例的编写实际上是两个q程Q用尚不存在的代码和定义这些代码的执行l果。所以一个TestCase也就应该包括两个部分——场景和断言。第一ơ写TestCase的h会有很大的不适应的感觉,因ؓ你之前所写的所有东襉K是在解决问题Q现在要你提出问题确实不大习惯,不过不用担心Q你正在做正的事情Q而这个世界上最隄事情也不在于如何解决问题Q而在于ask the right questionQ?/p>
[TDD能帮助我消除Bug吗?]
{:不能Q千万不要把“测试”和“除虫”Z谈!“除虫”是指程序员通过自己的努力来减少bug的数量(消除bugq样的字眼我们还是不要讲为好^_^Q,而“测试”是指程序员书写产品以外的一D代码来保产品能有效工作。虽然TDD所~写的测试用例在一定程度上为寻找bug提供了依据,但事实上Q按照TDD的方式进行的软g开发是不可能通过TDD再找到bug的(x我们前面说的“完工时完工”)Q你惛_Q当我们的代码完成的时候,所有的试用例都亮了绿灯,q时隐藏在代码中的bug一个都不会露出马脚来?/p>
但是Q如果要问“测试”和“除虫”之间有什么联p,我相信还是有很多话可以讲的,比如TDD事实上减了bug的数量,把查找bug战役的关注点从全U战场提升到代码战场以上。还有,bug的最可怕之处不在于隐藏之深Q而在于满天遍野。如果你发现了一个用户很不容易才能发现的bugQ那么不一定对工作做出了什么杰A(ch)献,但是如果你发CD代码中Qbug的密度或LE度q高Q那么恭喜你Q你应该抛弃q写这D代码了。TDD避免了这U情况,所以将Lbug的工作降低到了一个新的低度?/p>
[我该Z个Feature~写TestCaseq是Z个类~写TestCaseQ]
初学者常问的问题。虽然我们从TDD的说明书上看到应该ؓ一个特性编写相应的TestCaseQ但Z么著名的TDD大师所写的TestCase都是和类/Ҏ(gu)一一对应的呢Qؓ了解释这个问题,我和我的同事们都做了很多试验Q最后我们得C一个结论,虽然我不知道是否正确Q但是如果?zhn)没有{案Q可以姑且相信我们?/p>
我们的研I结果表明,通常在一个特性的开发开始时Q我们针对特性编写测试用例,如果(zhn)发现这个特性无法用TestCase表达Q那么请这个特性细分,直至(zhn)可以ؓ手上的特性写出TestCase为止。从q里开始是最安全的,它不会导致Q何设计上重大的失误。但是,随着(zhn)不断的重构代码Q不断的重构TestCaseQ不断的依据TDD的思想做下去,最后当产品伴随试用例集一起发布的时候,(zhn)就会不l意的发现经q重构以后的试用例很可能是和品中的类/Ҏ(gu)一一对应的?/p>
[什么时候应该将全部试都运行一遍?]
Good QuestionQ大师们要求我们每次重构之后都要完整的运行一遍测试用例。这个要求可以理解,因ؓ重构很可能会改变整个代码的结构或设计Q从而导致不可预见的后果Q但是如果我正在开发的是一个ERP怎么办?q行一遍完整的试用例可能花Ҏ(gu)个小Ӟ况且现在很多重构都是由工具做到的Q这个要求的可行性和前提条g都有所动摇。所以我认ؓ原则上你可以挑几个你觉得可能受到本次重构影响的TestCase去runQ但是如果运行整个测试包只要p数秒的时_那么不介意你按大师的要求d?/p>
[什么时候改q一个TestCaseQ]
增加的测试用例或重构以后的代码导致了原来的TestCase的失M效果Q变得无意义Q甚臛_能导致错误的l果Q这时是改进TestCase的最好时机。但是有时你会发玎ͼq样做仅仅导致了原来的TestCase在设计上是臃肿的Q或者是冗余的,q都不要紧,只要它没有失效,你仍然不用去改进它。记住,TestCase不是你的产品Q它不要好看Q也不要怎么太科学,甚至没有性能要求Q它只要能完成它的命就可以了——这也证明了我们后面所说的“用Ctrl-C/Ctrl-V~写试用例”的可行性?/p>
但是Q美国h的想法其实跟我们q是不太一P拿托巴赞的MindMap来说吧,其实画MindMap只是Z表现自己的思\Q或记忆某些重要的事情,但托却大家把MindMapL一件艺术品Q甚臌有很多艺术家把自q的抽象派MindMap拿出来帮助托做宣传。同P大师们也要求我们把TestCase写的跟代码一栯量精良,可我惌的是Q现在国内有几个公司能把产品的代码写的精良?Q还是一步一步慢慢来吧?/p>
[Z么原来通过的测试用例现在不能通过了?]
q是一个警报,Red AlertQ它可能表达了两层意思——都不是什么好意思—?Q你刚刚q行的重构可能失败了Q或存在一些错误未被发玎ͼ臛_重构的结果和原来的代码不{h(hun)了?Q你刚刚增加的TestCase所表达的意思跟前面已经有的TestCase相冲H,也就是说Q新增的功能q背了已有的设计Q这U情况大部分可能是之前的设计错了。但无论哪错了,无论是那层意思,x到这个问题的Ҏ(gu)都比TDD的正常工作要难?/p>
[我怎么知道那里该有一个方法还是该有一个类Q]
q个问题也是常常出现在我的脑中Q无Z是第一ơ接触TDD或者已l成为TDD专家Q这个问题都会缠l着你不放。不q问题的{案可以参考前面的“什么时候设计”一节,{案不是唯一的。其实多数时候你不必考虑未来Q今天只做今天的事,只要有重构工P从方法到cd从类到方法都很容易?/p>
[我要写一个TestCaseQ可是不知道从哪里开始?]
从最重要的事开始,what matters mostQ从脚下开始,从手头上的工作开始,从眼前的事开始。从一个没有UI的核心特性开始,从算法开始,或者从最有可能耽误旉的模块开始,从一个最严重的bug开始。这是TDDM者和鼠目寸光者的一个共同点Q不同点是前者早已成竹在胸?/p>
[Z么我的测试L看v来有Ҏ(gu)蠢?]
哦?是吗Q来Q握个手Q我的也是!不必担心q一点,事实上,大师们给的例子也相当愚蠢Q比如一个极端的例子是要写一个两个int变量相加的方法,大师先断a2+3=5Q再断言5+5=10Q难道这些代码不是很愚蠢吗?其实q只是一个极端的例子Q当你初ơ接触TDDӞ写这L(fng)代码没什么不好,以后当你熟练时就会发现这样写没必要了Q要CQ谦虚是通往TDD的必l之路!从经典开发方法{向TDD像从面向过E{向面向对象一样困难,你可能什么都懂,但你写出来的cL有一个纯OO的!我的同事q告诉我真正的太极拳Q其速度是很快的Q不比Q何一个快拌慢,但是初学者(通常是指学习太极拳的?0q_太不Ҏ(gu)把每个姿劉K做对Q所以只能慢慢来?/p>
[什么场合不适用TDDQ]
问的好,实有很多场合不适合使用TDD。比如对软g质量要求极高的军事或U研产品——神州六P人命兛_的Y件——医疗设备,{等Q再比如设计很重要必L前做好的软gQ这些都不适合TDDQ但是不适合TDD不代表不能写TestCaseQ只是作用不同,C不同|了?/p>
{Best Practise}
[微笑面对~译错误]
学生时代最x的是~译错误Q编译错误可能会被老师视ؓ上课不认真听评证据Q或者同学间怺嘲笑的砝码。甚至离开学校很多q的老程序员依然x它?yu)像x迟CP潜意识里g~译错误极有可能和工资挂钩(或者和智商挂钩Q反正都不是什么好事)。其实,只要提交到版本管理的代码没有~译错误可以了Q不要担心自己手上的代码的编译错误,通常Q编译错误都集中在下面三个方面:
Q?Q你的代码存在低U错?br />Q?Q由于某些Interface的实现尚不存在,所以被试代码无法~译
Q?Q由于某些代码尚不存在,所以测试代码无法编?br />h意第二点与第三点完全不同Q前者表明设计已存在Q而实C存在D的编译错误;后者则指仅有TestCase而其它什么都没有的情况,设计和实现都不存在,没有Interface也没有Implementation?/p>
另外Q编译器q有一个优点,那就是以最敏捷的n手告诉你Q你的代码中有那些错误。当然如果你拥有Eclipseq样可以及时提示~译错误的IDEQ就不需要这L(fng)功能了?/p>
[重视你的计划清单]
在非TDD的情况下Q尤其是传统的瀑布模型的情况下Q程序员不会不知道该做什么,事实上,L有设计或者别的什么制品在引导E序员开发。但是在TDD的情况下Q这U优势没有了Q所以一个计划清单对你来说十分重要,因ؓ你必自己发现该做什么。不同性格的h对于q一点会有不同的反应Q我怿qx做事没什么计划要依靠别h安排的hQ所谓将才)可能略有不适应Q不q不要紧QTasks和CalendarQ又U效率手册)早已成ؓC上班族的必备工具了;而^时工作生zd很有计划性的人,比如?)Q就会更喜欢q种自己可以掌控Plan的方式了?/p>
[废黜每日代码质量查]
如果我没有记错的话,PSP对于个h代码查的要求是蛮严格的,而同h在针对个人的问题上,TDD却徏议你废黜每日代码质量查,别v疑心Q因ZL在做TestCase要求你做的事情,q且L有办法(自动的)查代码有没有做到q些事情——红灯停l灯行,所以每日代码检查的旉可能被节省,对于一个严格的PSP实践者来_q个成本q是很可观的Q?/p>
此外Q对于每日代码质量检查的另一个好处,是帮助你认识自q代码Q全面的从宏观、微观、各个角度审视自q成果Q现在,当你依照TDD做事Ӟq个优点也不需要了Q还记得前面说的TDD的第二个优点吗,因ؓ你已l全面的使用了一遍你的代码,q完全可以达到目的?/p>
但是Q问题往往也ƈ不那么简单,现在有没有h能告诉我Q我如何全面审视我所写的试用例呢?别忘了,它们也是以代码的形式存在的哦。呵呵,但愿q个问题没有把你吓到Q因为我怿到目前ؓ止,它还不是瓉问题Q况且在~写产品代码的时候你q是会自ȝ发现很多试代码上的没考虑到的地方Q可以就此修改一下。道理就是如此,世界上没有Q何方法能代替你思考的q程Q所以也没有MҎ(gu)能阻止你犯错误,TDD仅能让你更容易发现这些错误而已?/p>
[如果无法完成一个大的测试,׃最的开始]
如果我无法开始怎么办,教科书上有个很好的例子:我要写一个电(sh)影列表的c,我不知道如何下手Q如何写试用例Q不要紧Q首先想象静态的l果Q如果我的电(sh)影列表刚刚徏立呢Q那么它应该是空的,OKQ就写这个断a吧,断言一个刚刚初始化的电(sh)影列表是I的。这不是愚蠢Q这是细节,奥运会五全能的金牌得主玛丽莲·金是这栯的:“成功h士的共同点在于……如果目标不够清晎ͼ他们会首先做通往成功道\上的每一个细步骤……”?/p>
[试~写自己的xUnit]
Kent Beck大家每当接触一个新的语a或开发^台的时候,p己写q个语言或^台的xUnitQ其实几乎所有常用的语言和^台都已经有了自己的xUnitQ而且都是大同异Q但是ؓ什么大师给Zq样的徏议呢。其实Kent Beck的意思是说通过q样的方式你可以很快的了解这个语a或^台的Ҏ(gu),而且xUnit实很简单,只要知道原理很快p写出来。这对于那些喜欢自己写底层代码的人,或者喜Ƣ控制力的h而言是个好消息?/p>
[善于使用Ctrl-C/Ctrl-V来编写TestCase]
不必担心TestCase会有代码冗余的问题,让它冗余好了?/p>
[永远都是功能FirstQ改q可以稍后进行]
上面q个标题q可以改成另外一句话Q避免过渡设计!
[淘汰陈旧的用例]
舍不得孩子套不着狹{不要可惜陈旧的用例Q因为它们可能从概念上已l是错误的了Q或仅仅会得出错误的l果Q或者在某次重构之后失去了意义。当然也不一定非要删除它们,从TestSuite中除去(JUnitQ或加上IgnoredQNUnitQ标{也是一个好办法?/p>
[用TestCase做试验]
如果你在开始某个特性或产品的开发之前对某个领域不太熟?zhn)或一无所知,或者对自己在该领域里的能力一无所知,那么你一定会选择做试验,在有单元试作工L(fng)情况下,你用TestCase做试验,q看h像你在写一个验证功能是否实现的TestCase一P而事实上也一P只不q你所验证的不是代码本w,而是q些代码所依赖的环境?/p>
[TestCase之间应该量独立]
保证单独q行一个TestCase是有意义的?/p>
[不仅试必须要通过的代码,q要试必须不能通过的代码]
q是一个小技巧,也是不同于设计思\的东ѝ像界的值或者ؕ码,或者类型不W的变量Q这些输入都可能会导致某个异常的抛出Q或者导致一个标C“illegal parameters”的q回|q两U情况你都应该测试。当然我们无法枚举所有错误的输入或外部环境,q就像我们无法枚举所有正的输入和外部环境一P只要TestCase能说明问题就可以了?/p>
[~写代码的第一步,是在TestCase中用Ctrl-C]
q是一个高U技巧,呃,是的Q我是这个意思,我不是说q个技巧难以掌握,而是说这个技巧当且仅当你已经是一个TDD高手Ӟ你才能体会到它的力。多ơ用TDD的h都有q样的体会,既然我的TestCase已经写的很好了,很能说明问题Qؓ什么我的代码不能从TestCase拯一些东西来呢。当Ӟq要求你的TestCase已经h很好的表达能力,比如断言f(5)=125的方式显然没有断af(5)=5^(5-2)表达更多的内宏V?/p>
[试用例包应该尽量设计成可以自动q行的]
如果产品是需要交付源代码的,那我们应该允许用户对代码q行修改或扩充后在自q环境下run整个试用例包。既焉常情况下的产品是可以自动运行的Q那Z么同样作Z付用L(fng)制品Q测试用例包׃是自动运行的呢?即产品不需要交付源代码Q测试用例包也应该设计成可以自动q行的,qؓ试部门或下一版本的开发h员提供了极大的便利?/p>
[只亮一盏红灯]
大师的徏议,前面已经提到了,仅仅是徏议?/p>
[用TestCase描述你发现的bug]
如果你在另一个部门的同事使用了你的代码,q且Q他发现了一个bugQ你猜他会怎么做?他会立即走到你的工位边上Q大声斥责说Q“你有bugQ”吗Q如果他胆敢q样对你Q对不vQ你一定要冷静下来Q不要当面回骂他Q相反你可以微微一W,然后心^气和的对他说Q“哦Q是吗?那么好吧Q给我一个TestCase证明一下。”现在局势已l倒向你这一边了Q如果他q没有准备好回答你这致命的一击,我猜他会感到非常愧Qƈ在内心责怪自己太莽撞。事实上Q如果他的TestCase没有q多的要求你的代码(而是按你们事前的契约Q,q且亮了U灯Q那么就可以定是你的bugQ反之,Ҏ(gu)则无理了。用TestCase描述bug的另一个好处是Q不会因Z后的修改而再ơ暴露这个bugQ它已经成ؓ你发布每一个版本之前所必须查的内容了?/p>
{关于单元试}
单元试的目标是
Keep the bar green to keep the code clean
q句话的含义是,事实上我们只做两件事情:让代码奏效(Keep the bar greenQ和让代码洁净QKeep the code cleanQ,前者是把事情做对,后者是把事情做好,两者既是TDD中的两顶帽子Q又是xUnit架构中的因果关系?/p>
单元试作ؓ软g试的一个类别,q是xUnit架构创造的Q而是很早有了。但是xUnit架构使得单元试变得直接、简单、高效和规范Q这也是单元试最q几q飞速发展成量一个开发工具和环境的主要指标之一的原因。正如Martin Fowler所_“Y件工E有史以来从没有如此众多的h大大收益于如此简单的代码Q”而且多数语言和^台的xUnit架构都是大同异Q有的仅是语a不同Q其中最有代表性的是JUnit和NUnitQ后者是前者的创新和扩展。一个单元测试框架xUnit应该Q?Q每个TestCase独立q行Q?Q每个TestCase可以独立和报告错误Q?Q易于在每次q行之前选择TestCase。下面是我枚丑և的xUnit框架的概念,q些概念构成了当前业界单元测试理论和工具的核心:
[试Ҏ(gu)/TestMethod]
试的最单位,直接表示Z码?/p>
[试用例/TestCase]
由多个测试方法组成,是一个完整的对象Q是很多TestRunner执行的最单位?/p>
[试容器/TestSuite]
由多个测试用例构成,意在把相同含义的试用例手动安排在一PTestSuite可以呈树(wi)状结构因而便于管理。在实现ӞTestSuite形式上往往也是一个TestCase或TestFixture?/p>
[断言/Assertion]
断言一般有三类Q分别是比较断言Q如assertEqualsQ,条g断言Q如isTrueQ,和断a工具Q如failQ?/p>
[试讑֤/TestFixture]
为每个测试用例安排一个SetUpҎ(gu)和一个TearDownҎ(gu)Q前者用于在执行该测试用例或该用例中的每个测试方法前调用以初始化某些内容Q后者在执行该测试用例或该用例中的每个方法之后调用,通常用来消除试对系l所做的修改?/p>
[期望异常/Expected Exception]
期望该测试方法抛出某U指定的异常Q作Z个“断a”内容,同时也防止因为合情合理的异常而意外的l止了测试过E?/p>
[U类/Category]
为测试用例分c,实际使用时一般有TestSuite׃再用CategoryQ有Category׃再用TestSuite?/p>
[忽略/Ignored]
讑֮该测试用例或试Ҏ(gu)被忽略,也就是不执行的意思。有些被抛弃的TestCase不愿删除Q可以定为Ignored?/p>
[试执行?TestRunner]
执行试的工P表示以何U方式执行测试,别误会,q可不是在代码中规定的,完全是与试内容无关的行为。比如文本方式,AWT方式Qswing方式Q或者Eclipse的一个视囄{?/p>
{实例QFibonacci数列}
下面的Sample展示TDDer是如何编写一个旨在生Fibonacci数列的方法?br />Q?Q首先写一个TCQ断afib(1) = 1;fib(2) = 1;q表C数列的第一个元素和W二个元素都??/p>
Q?Q上面这D代码不能编译通过QGreatQ——是的,我是说GreatQ当Ӟ如果你正在用的是Eclipse那你不需要编译,Eclipse会告诉你不存在fibҎ(gu)Q单击mark会问你要不要新徏一个fibҎ(gu)QOhQ当ӞZ让上面那个TC能通过Q我们这样写Q?/p>
Q?Q现在那个TC亮了l灯QwowQ应该庆一下了。接下来要增加TC的难度了Q测W三个元素?/p>
不过q样写还不太好看Q不如这样写Q?/p>
Q?Q新增加的断aD了红灯,Z扭{q一局势我们这样修改fibҎ(gu)Q其中部分代码是从上面的代码中Ctrl-C/Ctrl-V来的Q?/p>
Q?Q天哪,q真是个׃h写的代码Q是啊,不是吗?因ؓTC是产品的蓝本,产品只要恰好满TCok。所以事情发展到q个地步不是fibҎ(gu)的错Q而是TC的错Q于是TCq要q一步要求:
Q?Q上有政{下有对{?/p>
Q?Q好了,不玩了。现在已l不是贱不贱的问题了Q现在的问题是代码出C冗余Q所以我们要做的是——重构:
Q?Q好Q现在你已经fibҎ(gu)已经写完了吗Q错了,一个危险的错误Q你忘了错误的输入了。我们o0表示Fibonacci中没有这一V?/p>
then change the method fib to make the bar greanQ?/p>
Q?Q下班前最后一件事情,把TC也重构一下:
Q?0Q打完收工?/p>
{关于本文的写作}
在本文的写作q程中,作者也用到了TDD的思维Q事实上作者先构思要写一什么样的文章,然后写出q篇文章应该满的几个要求,包括功能的要求(要写些什么)和性能的要求(可读性如何)和质量的要求Q文字的要求Q,q些要求起初是一个也达不到的Q因为正文还一个字没有Q,在这U情况下作者的文章无法~译通过Qؓ了达到这些要求,作者不停的写啊写啊Q终于在花尽了两个月的心血之后完成了当初既定的所有要求(make the bar greenQ,随后作者整理了一下文章的l构Q重构)Q在满意的提交给了Blogpȝ之后Q作者穿上了一件绿色的汗衫Q趴在地上,学了两声青蛙叫。。。。。。。^_^
{后记QMartin Fowler在中国}
从本文正式完成到发表的几个小旉Q我偶然d了Martin Fowler先生北京访谈录,光提到了很多对试驱动开发的看法Q摘抄在此:
Martin FowlerQ当Ӟ值得׃半的旉来写单元试Q!因ؓ单元试能够使你更快的完成工作。无数次的实践已l证明这一炏V你的时间越是紧张,p要写单元试Q它看上LQ但实际上能够帮助你更快、更舒服地达到目的?br />Martin FowlerQ什么叫重要Q什么叫不重要?q是需要逐渐认识的,不是惛_然的。我为绝大多数的模块写单元测试,是有点烦人,但是当你意识到这工作的h(hun)值时Q你会欣然的?br />Martin FowlerQ对全世界的E序员我都是那么几条Q……第二,学习试驱动开发,q种新的Ҏ(gu)会改变你对于软g开发的看法。…?/font>
——《程序员》,2005q?月刊
{鸣谢}
fhawk
Dennis Chen
般若菩提
Kent Beck
Martin Fowler
c2.com
Q{载本文需注明出处QBrian Sun @ 爬树(wi)的泡[http://m.tkk7.com/briansun]Q?/p>