测试驱动开发介绍(TDD)

测试驱动开发是一种先开发测试的先进技术,即你在编写足够的产品代码用于测试和重构之前就编写测试。测试驱动开发的初衷是什么呢?一种观点是TDD是一种规范而不是校验。就是说它是在你编码之前就惯穿设计的一种思考。另一个观点是TDD是一种编码技术,就像Ron Jeffries喜欢说的那样TDD可用来编写干净的可工作的代码。尽管我把决定权留给读者,但我想以上两点各有其道理。



目录

一、 什么是TDD?... 1

二、 TDD与传统测试... 3

三、 TDD与文档... 4

四、 测试驱动数据库开发... 4

五、 TDD与敏捷模型驱动开发(AMDD)... 4

六、 为什么使用TDD?... 5

七、 小结... 5

八、 工具... 6



一、 什么是TDD?
先行测试开发(Test First Development - TFD)的步骤已在图一的UML活动图中概括出来了。首先快速加入测试以及足以使测试失败的代码。然后运行测试,当然可能由于速度的原因你只决定运行整个测试的一小部分,用于确认新测试的失败。你修改你的功能代码使此次测试通过。第四步是再测试此代码,如果还是失败那你可能还要继续修改你的代码直到通过测试为止。一旦通过试就再回到第一步重新做起(可能你首先要重构设计中任何重复的代码,从TFD转到TDD)。

图一:先行测试开发步骤

[img]http://images.cnblogs.com/cnblogs_com/dingsea/TDD/tfdSteps.jpg[/img]


我喜欢用以下简单的公式描述TDD:

TDD=TFD+重构

TDD和传统的测试是完全的两回事。你使用写功能代码之前编写测试代码这种方式来替代先写功能代码再追加测试代码。更多的,你以很小的步骤来做此事—一次只写一个测试代码和相应的功能代码。一个遵循TDD开发步骤的程序员会因为不是当前的功能代码而拒绝写新的直到有一个会失败的测试代码。实际上就算是多一行代码他们都是不愿意的,除非有新的测试。一旦有了测试代码他们才会做相应的开发来确认测试的通过(你的新功能和测试代码可能会扰乱现有的测试)。只要你的代码通过测试了,那就要重构它以确保代码质量。这在原则上听起来简单,但当你第一次用TDD开发步骤时它会证明(你)需要更多的训练,因为它很容易出现“脱节”而引起编写功能代码之前没有编写测试代码。结对编程(Williams and Kessler 2002)的一个优点就是你的搭档会帮助你跟踪。



TDD一个潜在的假设是你有一个可用的单元测试框架。尽管商业工具是一个可选的方案,但大多数敏捷开发人员还是愿意使用xUnit系列的开源工具,比如JUnit或VBUnit。没有这些工具TDD实际上是不可能的。图2是一个UML状态图,描述了人们是如何在典型的开发中使用xUnit工具的。这个图是Keith Ray.推荐给我的。

图2:通过xUnit框架进行测试

[img]http://images.cnblogs.com/cnblogs_com/dingsea/TDD/tddStates.jpg[/img]


Kent Beck,一位致力于在极限编程(XP,Beck 2000)中普及TDD的人,他为TDD定义了两条简单的规则(Beck 2003)。一,在自动测试失败时只编写业务代码;二,消除任何你找到的任何重复(的代码或设计)。Beck解释了这两条规则是如何展现复杂的个体以及如何组织行为:

你进行有机的设计,运行的代码能根据结果产生回馈;
你自己编写测试,不可能因为人家为你写测试而一天等20次;
你的开发环境必须要求能对小的更改作出快速响应(比如你要能快速编译和进行回归测试);
你的设计必须高内聚低偶合以使测试更容易(比如你的设计高度规范化,这样能让你进步而且你的系统也会更容易维护)。
对程序员来说则暗示着应该学习如何进行有效的单元测试。Beck的经验认为好的单元测试:
运行快(它们有快速安装,执行和中断);
在隔离环境中运行(你可以重新部署它们);
使用数据以便容易阅读和理解;
在需要的时候使用真实数据(如产品数据的拷贝);
一步一步向你的目标前进;


二、 TDD与传统测试
TDD原本是一种编程技术,它间接地确保你的代码能彻底地被单元测试检查。可是,它能做的不只这些。你仍然需要参考传统的一些测试比如功能测试、用户验收测试、系统集成测试等等。大部分的这些测试都可以在项目开始之前就进行,如果你选择这么做的话(而且你也应该这么做)。实际在XP里,项目负责人指定的用户验收测试在编码时或是更早就开始进行了。告诉项目负责人系统能适应需求,增强他的信心!



一个好的传统测试能发现一个或多个漏洞,此理论同样适用于TDD。当一个测试失败的时候你必须进行改进因为你知道你需要解决这个问题。更重要的是,当你的测试不再失败的时候你就可以清楚地知道成功了多少。TDD增强了你的信心因为它适应了预先定下的需求,你的系统能正常运行了,因此你再自信地开发下去。



像传统的测试一样,项目风险越大,就要更彻底地进行测试。传统测试和TDD中你都不可能为着完美而奋斗,代之的是测试系统的重要性。为了解释敏捷模型(Agile Modeling, AM),你应该“带着目的去测试”、知道为什么要测试以及测试是在什么等级。TDD为你带来的有趣的间接影响是,你的代码测试覆盖率是100%—每一行都被测试过了—这是传统测试所不能保证的(虽然它们推荐这么做)。一般来讲我会很负责任地说TDD的结果比传统技术更有意义。

如果(为一个功能)值得写代码,那么一定值得测试。如果不值得测试,那又何必浪费时间去写一些无用的代码呢?


三、 TDD与文档
大部分的程序员都不喜欢读现有系统的文档,他们更喜欢看代码。这也无可厚非。当要了解一个类或是操作的时候他们一般是先去找相关的示例代码调用。书写良好的单元测试正是这么做的—它为你的功能代码提供了工作指引—作为结果的,单元测试有效地成为你技术文档有意义的一部分。这暗示着预期要用到的文档必须实事求是。

四、 测试驱动数据库开发
直到写这篇文章的时候,在敏捷开发团队中仍然在讨论一个问题:“TDD是否能用于面向数据的开发?”正如你在图1中所看到的处理流程那样,没有一个步骤是用某种特定的语言来描述的,比如JAVA或是C#,即使它们是TDD的典型使用环境。为什么不能在你修改数据库结构之前写一个测试?为什么你不做一些改变,运行测试,然后根据要求重构你的(数据库)结构?在我看来你只需要选择这样的工作方式就行。



我猜测在短期内数据库TDD没有一般应用程序的TDD好使。第一个挑战就是工具的支持。虽然单元测试工具,比如DBUnit,在写此文的时候现在已经表现出其可用的一面了。一些DBA正在提升他们测试的质量,但我没有看到哪个TDD接近了数据库开发的目标。另一个挑战是单元测试工具在数据库团队中并不能被很好的接受,虽然这正在被改变。所以我希望的是在以后的几年里数据库TDD成长起来。第二,新的开发概念对于很多数据库专家来说是比较新的,其次作为结果,使用TDD方式的动机一直悬而未决。这种情况会影响了数据库专家的工具的可用性—由于传统的思维在数据库团队里起支配作用而使得大多数工具不支持先进的开发方式。我希望工具提供者能和范例同步,但我希望的是我们用开源工具来代替。第三,我希望的是大多数在面向数据工作不喜欢测试驱动开发只喜欢模型驱动开发的人,我之所以这么说是因为直到目前测试驱动开发还没有被大范围的考虑。另一个理由是目前很多数据库专家都是喜欢虚拟设计,喜欢模型驱动开发。

五、 TDD与敏捷模型驱动开发(AMDD)
将TDD与模型驱动开发(MDD)相比较如何?或者是说和敏捷模型驱动开发(AMDD)呢?我相信:

TDD缩短了编程反馈周期而AMDD缩短了建模反馈周期;
TDD提供详细规范(测试)而AMDD提供一般规范(数据模型);
TDD有助于开发中编写高质量代码而AMDD有助于在项目中同项目负责人和开发人员进行有效地沟通;
TDD能对你开发的软件有一个具体形态的描述,AMDD能让你的团队,包括项目负责人,向着一个共有的目标前进;
TDD提供了具体文档的具体反馈而AMDD对具体文档允许口头反馈(具体反馈需要程序员在代码中证明,而那样就是非敏捷模型的技术了);
TDD可通过关注代码的可调用和可测试来看你的设计是否整洁,而AMDD提供了一个机会让你在写代码之前思考;
TDD是非可视化的而AMDD是可视化的;
两种技术对传统开发人员来说都是新的,搞不好会不爽它们;
两种技术都支持螺旋式开发;


你会采用哪种?答案取决于你,你的同伴,你自己的偏爱。一些人是“可视化思考者”,或是叫空间思考者,他们喜欢通过画东西来思考。另一些人偏向于组织文字,非可视化者或是非空间思考者,他们工作中不擅长画图,喜欢用TDD的方式。当然更多的人是在这两种极端之前,凭借感觉来适当地使用两种技术。简而言之,两种技术都使用以获取两种技术中的优点。

如何结合这两种技术?AMDD应用在和你的项目负责人一起建模以帮助浏览需求以及需求在架构和设计中的充分体现(通常是简单的草图)。TDD是用于确保你开发代码的整洁、可靠的重要组成部分。最后的结果是你有一个高质量、符合项目负责人要求的工作系统。

六、 为什么使用TDD?
TDD的一个好处是能让你小步小步地写软件。这是我几年来一直推行的方法因为它要比大步完成更具生产力。假设你有一些新的功能代码,编译和测试它们。当测试失败的时候你有很好的机会来排错。你能很快发现错误并修复它,这些错误可能是需要写两行代码,远远好过于你写2000行代码。同时也意味着你的编译和回归测试加快了。可见小步处理更具魅力。一般来说我喜欢在重新编译和测试之前加入新的几行代码,一般来说是10行以下。



我想Bob Martin说的对,“编写单元测试更像一种设计行为,文档行为而不是验证行为。编写单元测试缩短了反馈周期读数,最小读数基于功能验证。”(Martin, Newkirk, and Koss 2003)



敏捷技术给大多数人带来的第一误会是只适用于小项目,也许就是几个人花几个月时间的那种,不是那种“真正”的大项目。这明显错了。Beck (2003)报道了在Smalltalk下一个完全测试驱动开发的项目,40人年,有250000行功能代码和250000行测试代码。在20分钟里要跑4000个测试,一天中要进行好几次完全的测试。虽然算是大项目了,但我以前参加过更大的,几百人年的工作量(用TDD完成),由此可见TDD适用于任何大小的系统。

七、 小结
测试驱动开发(TDD)是一种在添加新代码之前让你的测试代码出错的一种开发技术。TDD很快被敏捷开发人员采用来进行应用系统源代码开发,很快也会将被敏捷DBA用于数据库开发。TDD可以作为敏捷模型驱动开发的补充方法(AMDD)而且两者可以一起使用。TDD不能替代传统的测试,相反它定义一种验证方式来确保单元测试的有效性。TDD的另一个作用是测试代码可以作为代码示例,因此可以为我们提供编码规范。在我的经验看来,TDD在实际开发中表现的难以相信的出色以至于很多敏捷开发者考虑采用之。

八、 工具
以下是一些典型的可用的TDD工具,如果有建议请给我写信。

csUnit (.Net)
CUnit
DUnit (Delphi)
DBUnit
JUnit
OUnit
PHPUnit
PyUnit (Python)
NUnit
Test::Unit (Ruby)
VBUnit
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.敏捷开发强调测试先行,因为先编写测试代码,就可以有目的的预防某些bug的产生,要知道,治病不如预防!!!所以我个人觉得这个还是比较重要的,文件也不大,只有8M,但是高清。 2.本版本与网上其他资源不同之处在于,此版本可进行编辑,搜索,已进行内容识别扫描。可全选,可编辑,可剪切文字。 部分目录如下: 目录 第一部分资金实例 第1 章多币种资金··························································································································3 第2 章变质的对象························································································································10 第3 章一切均等····························································································································13 第4 章私有性·································································································............................... 16 第5 章法郎在诉说........................................................................................................................ 18 第6 章再谈一切均等.................................................................................................................... 21 第7 章苹果和桔子........................................................................................................................ 25 第8 章制造对象····························································································································27 第9 章我们所处的时代................................................................................................................ 31 第10 章有趣的Times 方法.…....….. …... …..... ….. ….... …... ….. ……….... …... ….. …….... ……... ……...... 36 第11 章万恶之源.......................................................................................................................... 41 第12 章加法,最后的部分..…..….. ….... …... ….... …..... …... ….. ….. …..... ….. …... …....... ……………· ….. 44 第13 章完成预期目标.................................................................................................................. 48 第14 章变化.................................................................................................................................. 53 第15 章混合货币.......................................................................................................................... 57 第16 章抽象,最后的工作.......................................................................................................... 61 第17 章资金实例回顾.................................................................................................................. 65 . 下一步是什么? •••••••••••·••••••••• 暹···········…...... 匿·…... …......... 霉.........…········· 暹....….. 查......................... 65 比喻66 JUnit 的向.法::::::::::::鲁....愈::::::::::::::::::::::::::::::::::::::::::::::::::::董:::::::::::::::::::::::::::::::::::::::::::::::::::::::66 代码统计.......................................... 夔················…................................................................ 麟..... 67 过程............................................................................................................................................ 68 了:回顾::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 第二部分xUnit 实例 第18 章步入xUnit ......................................... 簪.........…......... …....... ….... …..................................... 73 第19 章设置表格··················--.. ·········.. ··••• 暹........... 薹··································"······"·····…................... 77 第20 章后期整理................. 畛················............................................................ 爹...参................….... 80 第21 章计数.......................................................................................…................................... ….. 83 第22 章失败处理.......................................…... 窜........….. ….............................. ….. ….... …............... 86 第23 章如何组成一组测试...........雪…………………..………………………………………….. 霞...…………….. 88 第24 章xUnit 回顾.............雪...... 暹........... 匿········ 摹…················--雹............ …............ 霉….........…............. 93 第三部分测试驱动开发的模式 第25 章测试驱动开发模式会....................…........... 吻.....……..... ……....... 诊....………………………......... 97 测试(名词)暹.雪.... 雪......................…......................................... 崎................................................. 97 相互独立的测试(Isolated Test) ……..... …·…….......... …………………………...... …………….... 雀..... 98 测试列表(Test List) ................................................... 豪....................…..... …........................... 99 测试优先(Test First) 断言优先 (Assert First;·::::::::::::::::::::::二 ::::::::::::::::::::神: ....:::...:.......二二厂::::厂厂 100 101 测试数据(Test Data) .显然数据(Evident Dat~·;··:::::::::::::::::::::::::::::::::::::: 二二:::::::::::::::::::::::::::::::::::::::::::…::::: 102 103 第26 章不可运行状态模式104 一步测试(One Step Test)··:::::::::: 二:....:..:墓:::::::二:厂二二二::::::::::: 二勹二二::..二二:: 104 启动测试(Starter Test) ................................... 金.......…·······....................... 渗........................... 105 说明测试<Explanation Test) 106 学习测试(Leaming Test) .... 二二二二二二二二二二二二二二二二二二二二二二二: 106 另外的测试 回归测试(;~鲁酝已卢;比~~;噜:::::::::::::: 二..二:.:二二二二二二:.二:::::::::::::::::::::::::::: 108 107 ::开 闷:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::缴:惫:::::::::: 便宜的桌子,舒适的椅子…………........……·…………………· ……………..... …………………………... 110 第27 章测试模式................…........ ….......................... 愈............................................................... 111 子测试(Child Test) .......... 筝.............….................................... 噙.............................................. 111 模拟对象(Mock Object) . …...... 摹.......………………·……………………………………………………· …111 :::1言lf(:n~~~~·;···::::::::::二::::::::::::::::::::::::::::::::::::::::::::::: 二::.二:.:.. :::....}}: 清扫割试死角(Crash Test Dummy) . ……... ………· ……………... ……….. …………......... …….. ….. 114 昙需它需心为芯芯;沁五::::::::::::::::::::::::::::::::::::睿 ......查::::::::::::::::::::::::::::::::::::::::::: :~! 第2~伪!:~昙,~:动了二::.二:./.二:.二二二:...::二二:/二三:.靡:...二::::::::::::::::: !!; 三角法(Triangulation) .... 暹........ 参...................................................................佛....................... 119 显明实现(Obvious Impl ementatlon) ….................... 拳...............................…......................... 119 从一到多(One to Many) ........................................ …....... 匿.............….................................. 120 第29 章xUnit 模式 断言 (Assertion).. 二二二.二二二::::.二:::::::::::::::::::::::::看 :.:..令::::::::::::::::::::::::::::::::::::::: 122 122 固定设施(Fixture) ............................................................................................................... 123 ;古婴:哼宁:st(贮笠:飞F~~~~~-~...:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ~ 芦 异常测试(Exception Test) . …... ……....... …....... ………... …............... 争............. …·鲁............. 令奄.... 127 全部测试(All Tests) ..................... 耄..令......................................... 伞......................................... 127 第 3~命:巴尸尸式..:. .::.: ..: :::.,二:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ;~~ 值对象簪............... 逾............................ 雪... 潭.................................................................................... 131 盓:去:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ~!! 插入式对象 插入式选择霹:::::: 二::::::::::::::::::::::令: ........:噜:::::::::::::::::::::::::::::::::::::::::::::::::::::::::135 134 工厂方法.................................... 参·········"···········...........................................噜..............….......... 137 递归:::::::::参::::::::::::::::::::::::::::::::::::::::::参:::::::::::::::::::::::::::::::::::睿...集:::::::::::::::::::::::::::::::: :~; 收集参数 单例模式亭~~-;心如~;--·::::::::二二:.二二二二二二二二二二二二二二:.. :.二:../...: 140 141 第31 章重构........................................................................................................................…..... 142 调和差异( Reconcile Differences) . …………………….. ……………………........ 萼..........……….. …... 142 隔离变化(Isolate Change) 帚...……………………........ …...... ……………... …………· …….. ………….. 143 :芯:亡::~!:~~==~;··::: 勹....勹勹:::::::二/..::/厂:.二:::::::::二二二二二二:..::::: ;芯之笘:芦::兄芯立立e)鲁·:参:.:.:.:食::::::::: 俺.. :..:二:::::::::::::::::::::::: 二:参:..二::::::::::::::: 二.::::..:芯 转移方法(Move Method) ………· ….. ……..... ……….... ………..... ………............. ………………....... 147 方法对象(Method Object) .. …………· ……….. ……………......... ……………….... …………………….. 148 添加参数(Add Parameter) …….. ….. ……………………………..... ……………..... ……………..... ….... 149 把方法中的参数转变为构造函数中的参数••• 重..............................................……....... …........ 149 第32 章掌握TDD ….....…….. ……..... ………….. ……………………...... ……………………………….. …... 夸... 150 附录沁尸尸严:::::::::::::::::::::::::::::::::睿 :.二:::::::::: 二:.:::二:.二:::.:.:::..::.::.:.::::.:..::::.二.:::::二二:.:::二腐 附录B 斐波纳契数列.…………·.........·….. …………....... ·······………….. 睿... 夸................. ….............. 食摩.. 164

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值