TDD-Test Driver Development

转载: http://blog.csdn.net/m13666368773/article/details/7006912

TDD概述

TDD的全称是Test Driver Development,测试驱动开发。
就是开发要以测试为驱动。编码之前,测试先行。
代码都没有,我如何测试,我连要测的对象都没有啊?这好像是个问题。

TDD的哲学为我们解答了这个问题:先编写测试用例(没有代码之前这些测试用例一个也通不过),然后再写代码让这些测试用例通过。
更进一层的讲就是:编写足够的测试用例使测试失败,编写足够的代码是测试成功。我们编码的目的更加明确的。

TDD是大名鼎鼎的极限编程的一个最重要的设计工具之一(另一个是重构(Refactoring),这是它的荣誉。

TDD带来的实际上的好处有:

  1. 你会更加站在用户的角度去看你将要完成的产品,你要尽可能想到用户所有进行的操作。而不是从程序员的角度想用户应该会如何去使用我们的产品。

  2. 测试用例是在对功能进行测试。在写代码之前先写测试用例,可以对我们编写代码提供指导性的参考。防止我们漏掉一些功能。

  3. 它使我们对自己代码有了信心,因为我们事先设计好的所有测试用例都Pass了。

  4. 如果在更改代码后测试用例不能通过,我们可以根据不能通过的测试用例精确的定位问题,并轻而易举的解决的这个bug。

  5. 哈!我们的一整套完备的测试用例在这里替我们把关(把的什么关?),我们就可以十分安全的使用极限编程的另一个最重要的工具——重构。重构改变的是代码的内部结构,而不会改变外部接口功能。知道在做重构时测试用例是把的什么关了吧!很明显,测试用例是保证我们在进行重构时,不会影响到代码的外部接口功能。所以我刚刚说,我们进行的重构是十分安全的。

  6. 基于第5点,我们找到了重构的信心,必要时候你还可以痛痛快快的并且满怀信心的对代码做一场大的变革。这样我们的代码变得干净了,扩展性、可以维护性以及易理解性纷至沓来。

    扫描二维码关注公众号,回复: 2936865 查看本文章

    总结就是:
    首先站在客户方代码的立场,可以获得更好的api。
    其次可以改善软件质量,支持重构。
    其三,大幅减少debug时间。
    前期投入大,后期能大幅缩短开销,将问题发现在最源头。

TDD有这么多好处,但它也不是免费的午餐,它需要我们有设计完备的测试用例的能力(这项能力是长期理论与实践的结合体),否则你将会吃了亏编写了一大堆测试用例,却没测到点子上。可怕的是,你还对你“测试通过”的糟糕的代码满怀信心。

TDD的主旨是什么

TDD的主旨是高效,可能这个高效不是非常高的开发速度。
通常的软件开发过程是先写功能,然后再写测试。甚至有时候只进行某些方面的测试,或者有省事的就略去了某些细小功能的测试,或者是忘了对这些模块的测试。
这些看起来对软件影响不大,但是似乎有点过于自信了。因为我们是人,不是神,所以难免会出一些这样或那样的错误,而这些小的问题在项目整合起来以后进行排错是非常令人头疼的。
TDD的思想是以测试推动开发进程。因为我们在软件开发之前,每个程序单元的功能都已经确定了。程序员在理解完整个程序需求以后,直接进行开发,有可能会因为种种原因考虑不很周全,似乎功能实现的没有问题了,但是其中却可能隐藏着非常可怕的Bug。TDD促使开发人员先根据程序单元的功能编写测试代码,就像是先建一个模型,然后向里面浇注合适功能的代码。最后满足所有的测试验证了,才能正常通过测试,这个程序单元才算完成。
这样消除了开发人员主观性的对程序单元健壮性的评估,更客观的验证每一个程序单元的功能实现以及可能出现的Bug。
当然,这些操作都需要有大量的代码支持,所以费事是在所难免的,但是这点“费事”与健壮性非常强的代码相比,有些人还是偏向于使用TDD。

为什么要用TDD?

用TDD的方法可以使代码干净(代码重构的结果),测试覆盖率高(先写测试的结果),软件做集成测试的时候一般问题会比较少。
而且你敢改人家的代码,看到有fail的test case 证明你有改错人家的东西,看到所有的test case都过了的话,你也很有信心说,我没有改错,或程序不会因为我的改动而挂掉。

什么时候TDD?

TDD是在Unit Test, 也就是单元测试时用的方法。

什么地方TDD?

我觉得写任何代码都可以用TDD吧

如何TDD?

  1. 加入一个新的测试
  2. 运行下新加的测试,看到它失败(因为你还没写功能代码)
  3. 对开发代码做很小的修改,目的就是让新加的测试通过 (注意这里的目的)
  4. 运行所有的测试(test case),然后看到所有测试都通过了 (看到测试都变成绿色,一般都会小开心一下)
  5. 移掉重复的代码,对代码进行重构 (既包括功能代码,也包括测试代码。特别注意红色的字串 一般会有重复,还有一些代码可以抽出来变成公用方法,测试代码中同样的初始化和还原测试环境的代码,可以放到intilize和cleanup中去)

除此而外,还有一些步骤也是可以加入的,比方

  1. 在写测试代码前,先从需求出发,准备一个Test list (需要测到的功能的列表)。忘掉你该怎么实现,那是后面的事情。
  2. 每测完一个就用横线划掉。
  3. 如果发现有漏掉的test 就加到这个列表中(列表测完你的功能也就完成了)。

TDD的好处与不足

好处

  1. 测试代码都是从客户需求出发的,不是重实现出发的。测试更关注于对外部的接口。
  2. 软件的需求都被测试代码描叙得很清楚,可以减少很多不必要的文档(有些时候写文档- 时间比开发时间多多了, 需要一个专门写文档的,而且用的机会很少。这里我很喜欢敏捷开发中说的:Just enough)
  3. 每次都是很小的步骤,这样你就很集中注意解决一个问题。葛优说的:步子迈大了容易扯着蛋,步子大想的就多,容易忽视些东西, 容易出错。小而简单就是美
  4. 可以优化设计。如果有做过测试驱动开发的会发现,为了更好的,更容易的做单元测试。它逼着你面向接口编程和使用一些设计模式,自然设计就灵活了,耦合性也低。

缺点

  1. 有时候开发代码可能只有几行,可是测试代码可能比真正的代码要多很多。而且花时间想怎么测试。
  2. 可能不适合时间很紧的软件开发,更适合于产品和平台的开发

如何学习TDD?

我觉得最好且最快的方式就是 XP中提到的结对编程,一个有TDD经验的坐在”后面”,指导另一个不大熟悉的人,两人一起来完成一个类或模块的功能。

几个关键点

  1. 记得你是做单元测试,不是集成测试,你要测得仅仅是你的类的功能,不要去测别人类的功能,一定要知道测到什么程度就好了,剩下的可能是别人需要测的。
  2. 每次都是一小步,目的只是用最简单的方法让新加的test case过掉而已。
  3. 在改/加任何功能代码前,一定要先想是不是要改或加test case。
  4. 测试驱动产生的单元测试代码是代替不了集成测试的,它还是单元测试
  5. 测完记得清理测试环境,还原到测试之前的样子。

关于TDD的观点和争论

经常会与人讨论TDD。初时,我会很耐心的跟人解释TDD的种种好处,试图让他们能够皈依TDD,结果总不尽如人意,争论者总是可以抛出一些新的观点,逼迫着我重新认识TDD,甚至最低落时,我会怀疑TDD是不是真的有效。

通过反思,我发现,所有和我们直接在一起写代码的人,都没有质疑过TDD,而且一旦真正进入节奏,便乐此不疲。而与我们争论的人中,为数不少的对于TDD,或是浅尝辄止,或是压根没有碰过。换句话说,他们的问题都是“想”出来的。真正做起来是什么样子,他们自己也不知道。

网上的某些讨论也有着这种倾向,想出一个问题吓唬自己,还试图让别人认同自己,比如这个。对于这些人,着实没有必要浪费口舌。连电都没有,我怎么给你解释灯的都好处都是白搭的。况且,欲加之罪,何患无辞!

争论的人里面,有些人是实践过的,但是,结果很糟糕。我们的沟通常常是这样:
我:你怎么理解TDD?
对方:不就是先写测试后写代码吗?

原来TDD也可以没有重构啊!打开他们的测试,几屏都翻不完的测试,让人目眩神晕。
我:这么长的测试你怎么保证它的正确性呢?
对方:哦?没有想过。

测试错了,但无法证明究竟是测试写错了,还是代码写错了,我合作过的不少团队都出现过这样的情况。

问题到底出在哪?我想了很久。

通过与不同的团队的合作,我逐渐意识到,这些团队欠缺的根本不是TDD,他们压根不知道如何写好代码。对于这些人而言,即便他们知道TDD有着“红——绿——重构”的节奏,也不知道代码应该重构成什么样子。在他们眼里,重构和不重构,没有任何差别。

在他们原有的认识中,写代码就是完成功能。在这样的背景下,很多人每天都忙碌于在原有的代码上堆叠更多的代码。在合作团队里,有不少人工作才一两年,更有甚者,是工作后才开始写代码,他们对于写代码的认知仅仅停留在照猫画虎的阶段,甚至连最基本的编程技巧都还不了解。更可怕的是,他们的代码风格还在不断被后来者模仿。对于这些人来说,如果不改变他们对代码的认知,指望“所谓的TDD”改变一切无异于痴人说梦。

猜你喜欢

转载自blog.csdn.net/weixiao1999/article/details/55250480