Test-Driven Development?别逗了
这篇文章来源于Peter Sergeant在Write More Test 博客上的《Test-Driven Development? Give me a break…》,在原文和Reddit 上有很大反响。这篇文章里的很多观点在《TDD并不是看上去的那么美》和《再谈敏捷和TW咨询师》里都出现过(我个人觉得我的观点比其更全面一些)。就像我转的《Scrum为什么不行》 和《Bob大叔和Jim Coplien对TDD的论战》一样,从这些贴子我们可以看到——这是一个全世界的问题,并不是只有在中国才有的问题。
很多敏粉都在说我在是喷敏捷,黑敏捷,向敏捷泼脏水,我只想对这些人说——你们这样的见解很肤浅也很敏感,你们根本就没有认识到——争论,反思和不同观点的意义,你也就无法了解你们所信仰的敏捷!你们只是在肤浅和盲目地信仰和教条敏捷中的许多名词、方法和标准答案罢了。
——————————————正文开始——————————————
对于程序员来说有些事有非常危险的信号(red flag)。当我听到有人开始信仰Test-Driven Development 是 One True Programming Methodology(唯一正确的编程方法论),这就是危险信号(red flag),我开始假设你是一个劣等、没有经验的程序员,或是某些敏捷咨询师。
测试只是一个工具来帮助你,而不是用来证明谁比谁更虔诚,或是我的屌比你的要大,等这种愚蠢的行为。测试是用来让程序员得到有帮助的、更快的反馈,从而找到正确的路径,如果你搞坏一些事,其还可以用来给后人一些警告。这根本就不是一个神秘的有魔力的方法其可以让你的代码变得更好……
整个Test-Driven Development的概念是麻痹和信奉,从而让其成为你的人生观。相反的:Developer-Driven Testing,它给你和你的同事一些有用的工具来解决问题,来支持你自己,而不是那种以工具或方法为中心的让你假设其应该是那样的测试。
是不是在有些时候我们需要在写代码前写测试?当然是,比如,“修改已有的功能”,这会一个适用的场景,还有那些短小的和已定义完善的事物,或是对已被测试过的代码做一些改善。
但, 是不是你就应该需要总是要去先写测试?省省吧,别逗了。
这是极度白痴的行为,尤其是在设计,调查和开发的初期。让你的测试来接管你的代码(而不是影响那个模块的代码)和接管你的设计 这是一个巨大的失败,就是因为你写的那些测试范围太大太不靠谱。(陈皓注:我在《TDD并不是看上去的那么美》一文中说过测试案例的测试范围的问题,敏捷社区除了对我进行人身攻击外从未对此做过正面回答。)
在写代码前写测试案例在一些场景下的确很不错。然后,Test Driven Development,被敏捷专家或是其它各种五花八门的江湖骗子像神给凡人宣扬一样,这就是欺骗大众。
行动在想法之下,于是测试必需先行(所有我已看到的,所有我正在看到的都表明这是TDD的中心思想—— 你写了测试,然后你再写代码并通过测试),于是测试成为了最有用的活动并可以帮助程序员。这是错的。
就算你在一开始要写一些测试案例,但只要你想让这些测试案例更有意义,那么,你要么得让这些测试案例的测试范围更小更底层更精确,要么你就得在整个软件快要写完的时候再去写测试,要不然你就得欺骗或是篡改测试案例。在为数不多的情形下,前者是正确的——测试围绕于bug,或是小的,定义地很好的功能碎片(陈皓注:我个人理解为单元测试是目前最有效的))
把测试变成整个活动的中心因为其对程序员有用?真牛逼。老实说,控制程序员的工作流程只可能得出一条无比正确的答案——荒谬可笑。
测试帮助程序员,是因为其可以帮程序员组织自动化测试,所以才帮了程序员,而不是cargo-cult(货物崇拜,参看《各种流行的编程方法》中的cargo-cult编程)——信仰一种工作流程并让所有的人或事来适应于他。
先写测试这种方法只会在“Developer Driven Testing”(程序员自己驱动的测试)下可行——关注于选取一个正确的方法让程序员更有生产力。生成一堆测试的规则并说这是唯一的真理是不正确的。
一些讨论和想法(在此贴发出数小时后)…
当我这篇博文发出几个小时后,其被转到了别的地方并引发了一些讨论。
在 Hacker News 上,有人说我提出了很多很不错的问题,并且那是真正的有理有据的观点。我在用用户名叫peteretep 的回复了一些。
在 Reddit 上的争论更多更强。那里有很多的人觉得需要写自动化测试。并且这篇博文被大家演变成拥护测试和可实践的建议,我觉得我是误传达了我的想法,我觉得软件测试是非常重要的,而不是根据哪个方法论进行的教条主义!
——————————————正文结束——————————————
我在Reddit上看到了下面的事,我也作些评论。
- 大家在讨论很多很多的技术细节,比如如何测试私有方法,如何测试inner class,甚至还有代码。我太喜欢了,这才是真正的讨论,而不是像酷壳这边那些敏粉们说人而不说事的讨论,那些所谓的敏捷咨询师的话里连一点技术细节都没有。
- 并且也有人说TDD可以让你去Design,但随后就有人说,正真的Design就是Design,而不是hack 测试来强行让你Design。后面有了附和到——有很多思想意识想用流程来代替思考,软件开发就是需要在某中上下文下去思考,而不是使用某种机制来让你思考 。
- 我看了两极分化的大量的争论,这是我最喜欢看到事。世界就是因为有不同的观点而美好。有反对才有争论,有争论才有思考,这才是进步的源泉,而不是统一认识,形成标准。而对于那些党同伐异的,一听到有反对声就激动就要打压的敏粉来说,我只能认为他们的人生观世界观扭曲得就像朝鲜那样。
(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)
《Test-Driven Development?别逗了》的相关评论
浩也忍不住了,又一击重拳。你自己都写了,Test-Driven Development. 他只是一种drive, 是用来develop的。用他是有适用范围的。我想大家都明白,不要再自以为是地说他不能design了。
另外我一点都没看出你诸多有关敏捷讨论的文章中有什么技术细节。除了说 if(浩哥 or 大师){perfect design;} else if(敏捷){shit;}这样的代码以外。
不要说我又在骂人,如果听不得反对的声音,那我不会再发帖了。python和开源中国上有很多好的文章,我也大可不必在你的YY天堂里浪费时间敲键盘了。
dick-swinging my Cucumber is bigger than yours idiocy
x爆了。。。
同意争论,赞成争论,也反对任何形式的神话和盲目崇拜,更讨厌打压异己。不过文章里的观点也是有些偏激的,个人感觉。
有这样的心态就非常好。另,我主要是想让大家去看看国外的程序员是怎么思考和讨论的。
开发者精力在创新,周密(对一处改动导致原来可靠的地方的影响)可能不足,有测试人员的帮助,应该不是什么坏事
一直都没觉得TDD靠谱, 他不能提升程序员和项目经理的内功, 所以他不能提升软件质量
再强调一下,TDD本来就不是用来提升产品质量和增加内功的,要增加内功应该练习葵花宝典。
其实TDD只适用于一些小型的,短周期的应用开发。其主要意图是避免冗余设计。不要再骂石头不能孵小鸡了。
我不了解皓哥和咨询师的恩怨史,但我能清楚了解你看到他们言论时候被恶心到了,就像我看到你对敏捷的言论一样。所以个人觉得还不如直接对他们人身攻击来得痛快,不要再拿敏捷本身说事了。
我最近才开始进行TDD式的开发
单元测试确实帮我省了不少心,起码能够明显感觉到代码的可靠性在编代码的过程中就能得到保证,而之前都是需要一个测试客户端(我做的是服务器后台开发)手动测试,现在,我已经体会到了别人所说的:“测试没写,怎么写代码啊?”感觉了。
我的体会,在完成绝大多数的具体实现(某个class的某个方法)时,使用测试驱动开发是非常有必要的。
“我个人理解为单元测试是目前最有效的”
个人的理解对于函数之间耦合情况严重、大量使用全局变量和复杂结构体传递参数、多个函数乃至多模块协同完成链条很长的功能、中间结果难以观察的系统,单元测试的效果会非常糟糕。UT对于新产品、小型规模、结构清晰的产品(尤其是几个人开发的那种)可能会有较好效果。
测试驱动设计和开发暂且不论这种方式如何,就形式上就存在一些问题。大多数专职测试人员只具备执行能力根本无法达到预期目的(甚至都开始打算使用外包方式);对于兼职测试,那么测试驱动开发和开发驱动测试区别真的就不大了,同一个人做的东西,在交付压力下作假太简单了,就像CMM的时候为了达到自检缺陷密度自己制造缺陷报告一样。
@陈皓 恩,应该跳出思维的圈子,用第三者的角度思考一下,赞同!拒绝传教式的宣讲,相信没有银弹!
首先说我没用过TDD,所说的都是自己想的。我认为,TDD主要是针对业务大方向的,针对于一些业务接口,接口一般来讲是不会了生变化的,否则也没有必要抽象出接口了.这样能保证业务上不会出错。至于具体实现,还是做单元测试比较好,一个业务接口,实现的方式不一样,每种方式可能都会涉及到很多的类及方法,而在实际开发过程中很难一次选中最合适的方法,这样,如果像单位测试一样针对每个类每个方法做TDD,一旦实现方法需要变动,会累死人的。而且也会迷失在一些小的实现细节上,忘了最主要的业务需求。
把一个方法论搞的和宗教似的,就是一件挺可悲的事。
认为它能解决软件工程中的所以问题,更是可笑(我一直不赞成软件‘工程’这词)。
Never argue with a fool.
~~你找工作面试,就得面对教条和标准答案,这就是现状。当然,在面对能给你¥的人面前教条,在内心深处灵活、质疑,是一种很痛苦的分裂。
再顶这句:”你要么得让这些测试案例的测试范围更小更底层更精确“——没错!TDD只有在这种情况下才是利器。
首先要搞清楚什么样的系统适合Agile过程来进行开发。如果一个系统规模庞大,Agile就不适合它。
Agile适合小的系统——代码量<5(?)W行,开发人员少于10(?)人,TDD是Agile的支柱之一,因此编写单元测试作为小型系统中TDD的开始,就是必须的了。即便如此,Design和Architecture依然无法使用TDD。
如果有一种方法能够对Design和Architecture进行单元测试的话,TD Design及TD Architecture未尝不可。
@raof01
不要在楼主这样的圣人面前说出这种世俗的话.
表示我只在设计确定之后,才会开始让单元测试介入进去。我也经历过用TDD来做design的时候,后来发现严重不靠谱——当然主要原因是这并不适合我,我设计比较喜欢推导,而不是靠感觉。因为一个系统并不总是从最外围的interface开始做的,而TDD会让你不知不觉的走这条道路。
千万别跟扫特沃克斯的人争论
@raof01
可能是我真的没做过TDD,感受不到你所说的,但我的感觉是TDD的测试是业务上的,应该很大的那种,只要能确定你的业务实现有错误就OK了。举个例子,买一个100商品,某一时段打折后是89,在令一时段打折是94.而在做测试的时候,只要给出商品价格和时段,你返给我89或94就可以了,返回的正确就OK,返回不正确,就说明你功能有问题。具体打折代码怎么实现,用了多少个类,多少个方法我没啥关系!
@vczh
用推导来做设计很靠谱,逻辑会很严谨,但可能会忽略一些例外。而且你该尝试别的设计方法了,不能一根筋,要两头堵啊,哈哈。当然,应该是看见钉子,找锤子,而不是拿着锤子找钉子。
@消失风雨中
测试要是关心实现的话,要么是你太好奇,要么是实现做得很烂。
Why TDD? It is all about costs.
Communication is for making the process smooth, and the cost will go down as a result.
TDD is for making the application/software/class/function just work, no more no less. Because of the restrictions on time, budget, and other resources.
TDD的优点之一:从一开始就让测试人员介入进来,理解需求。在整个流程中促进了测试人员和开发人员、业务的交流。对开发人员来说,其实就是自顶而下的设计方法,先关注高层需求,设计,不要过早的陷入底层细节。配合快速完成原型交给用户反馈,然后改进提升性能。
同意没有银弹,但也不能否认TDD的好处。
@lxu4net
你讲的“先关注高层需求,设计,不要过早的陷入底层细节”这些恰好是TDD的不足,TDD没有这些优点。
还是版本管理器,如git,好。
@raof01
所以这可以通过后期引入TDD来弥补,不能操之过急。
@lxu4net
“一开始就让测试人员介入进来”和“TDD”是两个互相独立没有关系的东西,不要混为一谈。
@Todd
TDD不同于UnitTest,从集成测试用例入手,自顶而下开发,所以我说“先关注高层需求,设计,不要过早的陷入底层细节”
@lxu4net
你说的是ATDD吧。现在ATDD还很不成熟,停留在概念上,应用范围比较窄。ATDD不适用的场景很多,最典型的就是游戏,游戏的细节需求要在运行过程中不断调整的,不可能在实现之前写测试用例。另外,最优化系统ATDD也不适用,比如:搜索引擎、自动化翻译、推荐系统,这类最优化系统的特点是没有绝对正确的结果,只有相对的评价指标,不会事先把结果精确写成用例。
@陈皓 “法乎其上,得乎其中”。谁也不会真以为那些最早提出来这些概念的人真这么死板和教条,这只不过是一种宣传策略而已。但让人不爽的一点是,IT界里,按理说应该是聪明人多一点,用不着搞这么些类似于“传销”的夸张手法。大可以直接说“反清复明就是个幌子,是对蠢人说的。对聪明人,直接点,就是抢回我们的钱财和女人!”
测试驱动开发?测试用例也是被开发出来的啊,这到底是什么关系。写一个好的软件,关键不在测试,而在程序员的严密的逻辑思维和编程技艺的高超。
本质上讲的话,以上所谓的测试驱动应该是需求驱动吧?
@kekec
你要承认,烂程序员是需要管理的。所以不要小看这些教条的价值。
@vczh
The problem is dumb programmer don’t think they are dumb, and everyone could be dumb in some circumstances.
The most popular mistake programmers make is being over-confident.
There is one and only one Steve Jobs, let’s go back and face the reality.
作为一个没有很多编程经验的我来讲讲我对TDD的看法:TDD就像考试,考试只是在看一个人的水平如何,而你几乎不能从考试中真正学到任何有价值的东西,真正有用的是学习和思考的过程。
不知道我理解的是否到位?请批评指正。
对业务系统来说,测试场景和测试数据是TDD的关键,而不是写多少的测试代码。
而测试场景和测试数据的设计,是业务能力,不是技术能力。
我看这篇文章出来攻击也没有什么有力的论点,或者有论点也是单方面的论点。这对于tdd的攻击有比你受到的攻击好到哪里去。
TDD的确很难,并且其创始者也从未宣称过它适合于所有的开发活动。但是不能因为一个药不能包治百病,就说这个药是废物。我不是一个坚定的TDD的实践者,但是我的确相信TDD对于设计的影响。TDD是关于设计的,而不是关于测试的,测试是其的一个非常好的副产品。很多时候我开发是TDD与传统方式向结合,但是一旦有可能,或者条件/情景适合,我会尽量做TDD。对我触动最大的一件事是,有个项目的一个模块,我已经用我driven的设计完成了2/3了,然后突然觉得应该用TDD试试(当时没有时间压力),然后很快的做完了(以为会多花时间,但并没有多)。然后回顾两个设计所产生的结果,发现由TDD而带来的自然而然的结果比原来的要优雅很多,也简单很多。你可以说我是个笨蛋,无法developer driven一个好的设计。但是这是事实。
@tcmaster
天哪,您举出的例子实在是太简略了,就像是在描述一个童话。如果您希望您的例子可以有说服力,请把例子描述得详细一些。最好有数字和精确的词汇,而不是感觉。这样的例子只会产生副作用。
另外,看了些评论,似乎有人认为TDD是为了避免差的程序员对项目产生额度影响。我觉得不管是TDD,SCRUM还是AGILE,假设他们能够工作,那么有一个基础就是程序员的素质。没有素质可以免谈了
看了博主的这些个帖子,感觉缺乏细致的分析和论证,大多是概括性的结论。分析不是推倒式的,而是先立命题,然后搜罗证据来佐证,又接受不得别人的批评。果断得在weibo里不再粉博主了
好多方法论的引入成功与否,最直接的就是执行方法的人群,一个“来着不惧”的组织,什么方法指导起来都那么困难。TDD对于Developers的综合要求还是蛮高的,这样的话不好说是Developer成就了TDD,还是反之。
你说的这个现象不止在Agile领域有,我感觉身边或者认识的一些人对Linux也持有类似的态度。就是有点无道理的狂热。不过也可能是我的感觉不对。
测试驱动据我个人经验还是非常重要的一个环节。过分相信测试驱动也会代价比较大,特别是测试周期特别长的项目,但是也不至于被否定成这样。测试驱动自然有它的优势和劣势,有适用场景和不适用场景。它在理论和概念上也有它特定的位置。
博主这样批TDD有吸引眼球嫌疑,起码kent提出TDD是他自己多年实践中提出的解决问题的方法,我认同博主对不同的项目不同的情况使用不同的应对方法,光靠TDD无法解决所有的问题,我个人也推崇最佳实践。TW和infoQ宣传敏捷是个积极的态度,国内大部分还是传统瀑布高层设计-dd-编码-测试,中间大部分是文档,XP明显是针对这些弊端而设计,我个人的经验使用了部分XP中内容后代码质量明显改善。如果你觉得TDD不好请说出你的最佳实践给大家分享。看人是看他做什么而不是说什么,博主明显是在剑走边锋!
没有深厚的功力,再精妙的招式也只是花拳绣腿。
TDD是有限制的,并不是所有的项目都适合使用这种模式,而且,TDD最初的目的是为了预防BUG扩散的,先定下预期目标,然后实现,以避免隐藏的BUG被后续引用而导致bug扩散。
我想每个人都认同:做任何事情是在正确的基础上做得更优秀。TDD就是这个思想,不管你开发如何改变和优化设计,都要保证功能正确。TDD可以让一个普通的入门级的程序员就能把事情做正确,不需要类似搂主这么高级的开发人才就能把产品功能做对了。这就是很有价值的了。当然TDD再加上搂主这么高级的开发人才,那就是既能做对事情,又能把事情做得很优秀。TDD没有什么不好。