Kevin-moon

学习在于分享
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

我真的就只能在远方看你吗?!!! "测试驱动开发(TDD)"

Posted on 2008-12-15 09:02  Kevin-moon  阅读(2665)  评论(30编辑  收藏  举报

  最近听到了很多关于软件质量的话题,自己前段时间也参加个PMP(项目管理)的培训,所以一时对于质量控制特别感兴趣,在这里想和大家共同讨论下!
  软件质量,是所有人都很关心的东西。我们在开发过程中为了保证质量,从中引进了软件测试。它在整个的过程中起到的作用不言而预,但是它也存在一些问题:
  1、在软件测试中要保证软件的高质量就必须增加项目的成本,从而需要增加测试人员,延长项目时间,购买或学习测试工具的成本。
  2、因为这种测试是依赖与开发完后才提交给测试人员的,所以如果测试中出现BUG,就会出现BUG打回,再次提交测试...,这中间还需要测试人员和开发人员的沟通,这也是一个成本的增加
  3、这种方式会使得开发人员对测试人员产生依赖,从而降低代码的质量,减少自己的测试.....

  
  我们为什么不能把测试前移呢!让开发人员自己对软件的业务就做个完整的测试,然后把代码提交给测试人员,这样就可以减少BUG的数量,同时可以让测试人员不只关注与功能性的问题,可以关注更深层次的问题(性能,用户体验...),这种方式就是做单元测试。其实这个东西很早就有了,每个人都知道它,只是如何做的问题,我相信其实很多公司都做到,有些做的很好,但也有些是失败的!我自己经历过失败,体会过它的麻烦和迷惑,也经历了成功,体会到了它的好处。所以把这些写出来分享下!


  软件就是由代码组成的,所以软件的质量就是代码的质量,我们出了BUG就从代码开始入手找问题,然后修改代码。但是当你的软件从小慢慢变大时候,代码越来越多,彼此之间的关联越来越紧密,这样就带来了一个问题"修改一部分代码后会影响多少?",如果你拿这个问题去问那些项目中没有单元测试的开发人员,他们给出的答案都是通过"拍脑袋"来的,这样绝对会给你的项目带来风险。为了降低风险,项目开始要求开发人员做单元测试,但是做过后得出,这真的可以降低成本吗!花了太多的时间去写测试代码(甚至比开发时间还要多),对于质量的保证也没有达到预期的效果...,项目做完后,发现做单元测试的和没有做成本多很多,所以接着就放弃了!..... 这种现象我想是我们都想做它但又不做它的最大因素。
  其实我想大家对它的理解有点误差,我认为他最大的用处不是用来测试代码,而是测试设计!!代码从是设计来的,保证了设计的正确性不也保证了代码嘛!软件中的未知风险太多了,其实很多出于设计,对于设计很难去评价好,还是坏,很难找到一个衡量的标准,但是我想TDD,给了我们一个标准,虽然不能去完整的评价,但至少可以是一部分,可以降低它的风险。
  这里慢慢开始引入了本文的主题,测试驱动开发(TDD)。我的理解上,单元测试如果不是TDD这种模式,就没有太多的必要去做,因为那样投入做单元测试的成本和收益之间找不到平衡点。

"测试驱动开发"的经历


     测试驱动开发简称TTD,全名Test-Driven Developmentd。它是敏捷开发的一个重要组成部分,来源与"极限编程"。我接触它是从一年前的那天(具体时间不记得了~ 呵呵!)开始的.....

接触


     记得两年前的某天,我正在公司偷偷地看电视剧"奋斗",这时看到邮箱中的一封邮件: 部门下了一个确定"要求每个项目开发过程中加入单元测试"。当我听到"单元测试"的时候,满头的问号,"它是什么东西,做什么用的....?"(当时还很菜,居然还听过单元测试...!),接着不停的开始找资料,足足花了一个星期才把它了解,然后做了一个简单的DEMO,写些简单的测试代码,把它放到Nunit上,看着都是通过的提示,兴奋呀!
  这时就和项目中的一个"大牛"开始讨论它了,忽然"大牛"的口中蹦出了三个英文单词"TDD",然后和我讲了一大堆,我根本就不知道他说什么(水平有限,当时理解不了),只是重复着三个字"明白了"。接着他说,项目的这个版本你设计的时候,加入单元测试吧,如果可以的话,也试下TDD.....
  我是一个喜欢挑战的人,所以一开始就玩先写测试代码,结果呢!大家都明白,菜鸟嘛!一定失败咯,其中的原因是:根本就没有"测试驱动开发"的思想,完全不知道如何开始先写测试代码,而且还没有理解MOCK!下面只有乖乖地和别人一样,等代码写完后再写测试代码。  
  就在代码写完,开始写测试代码的时候,我们项目组内的人都遇到了相同的问题:
  1、系统中程序之间的偶合度太强,业务层,UI,数据层依赖了太多的环境因素,很难分开,所以写测试代码前,还需要去虚拟很多东西
  2、花了一天把需要虚拟的东西都做完后,又出现了一个最重要的问题,测试代码太多了,实在写不下去了,一个测试方法(业务比较复杂的)花了半天的时间,这比我写代码时间还多

  之后为了完成任务只写了几个简单的测试代码提交。不久,其他项目组也遇到了这些问题,所以公司最后停止了这个过程。我当时听到这个消息的时候,心里有点不好受,因为从那时起我就觉得这是很好的过程,出现的这些问题只因为我们的实力还不够,同时它对于开发人员来说也是一个挑战,一个提高。可现在停止了,意味着失去了一个很好的锻炼平台。
     出于不甘心失败,自己暗暗下决心,一定要提高自己的实力,一定要在设计前就写好测试代码!.....

迷茫


     在之后的一两个月的时间内是很迷茫的,虽然自己下了决心,却不知道从何开始,盲目地在网上找资料,发现有意义的资料太少,身边虽然有牛人在,但是这个东西是只能意会不能言传的。去公司的图书馆找了些关于敏捷开发和极限编程的书,看完后体会还真是挺深的,加强了对"测试驱动开发"的认识,可自己还是不会.......!!
  那时的自己连设计模式都不会几个,好象连接口interface都不太会用,至于抽象还是刚刚理解的阶段,对于单元测试,还没有学会MOCK。
     不过我的运气还真好,就在这个时候,有个朋友找到我说,有个小项目需要帮忙,问我是否参与呢,由我来负责架构和设计(现在想想,他还真有魄力,敢让我这个菜鸟来架构),我那时也很闲,而且正想找个实验的项目呢!于是就答应下来了。
     项目其实很简单,外贸公司用于发布产品和网上销售的网站。用户数也没有要求,小公司要求可以用就可以了。花了一段时间接触客户,做出了简单的项目计划,基本完成了用户需求,然后就开始做基本架构了,架构还是用经典的三层模式,数据库选的是MYSQL,没有用O/R Mapping....这些第三方的框架。因为出于实践和学习,所以希望都通过自己手写来完成。接下来开始做具体的设计了,花了几天的时间做完了大概的设计,画完了UML图.....,就剩下代码了!
     "单元测试",任然加入了我的开发过程,在这里我总结了一开始失败的原因,加上自己这段时间的学习,知道了要减少程序之间的偶合度,减少依赖。可是真到写的时候,又迷茫了.....

成熟


     经过了一段时间的迷茫和设计的不断返工,计划的不断延误。终于开始认清了真相,也真的理解了一句话,"质量是设计出来!",同时明白了"抽象"的必要性,并且还是会使用MOCK了!
  哎~,这些收获付出了很多的代价呀!项目的合伙人因为计划不断厌恶,想杀我心都有,每次去用户那里,用户总语气很怪强调"专家"这两个字(我朋友为了接项目,忽悠客户说我是很牛的专家...),我顶着这些压力,还在不停的重构,不停的写着测试代码。
  不过,单元测试的过程并没有很大的改善,主要还是一个复杂的方法里面的业务规则很多,而且代码也多,方法内部依赖的环境因素和依赖对象也很多,当出现这种情况的时候,去写它的测试代码简直是一个十分痛苦的事情,而且这种应付不了以后的变化。这种代码代码本来就多,当需要变化的时候,看代码就需要N久时间,更别说还有心情在去理会测试代码了!我对于这种问题并没有太多的解决办法,只是用时间去填补。
     其实经过了这些,我知道自己欠缺什么?!那就是设计,由于设计的不够抽象,对于复杂事物分解的不够简单...,接着跑出去书城,拿着刚发的工资买了N多的关于设计的书籍。把它们抱回家,当看着这些书的时候,看着正在进行的项目,和那一大堆比代码还复杂的测试代码,觉得值了!

飞跃


     "单一职责"
     "依赖倒置"
     "开放封闭"
     "Liskov替换原则"
     "迪米特法则"

     这些设计的基本原则,大家是否是已经看过了太多次了,但是这些你真的每个都理解了吗?23种设计模式,每种模式都会了吗!会使用吗!你做设计的时候,是否会去思考我应该用何种模式呢?!......
  这是我花了N久时间才慢慢理解和学会的东西。时间大概过了半年多,我的小项目已经开始运行,看着它正常的运行和VS2005上测试项目中的一排"测试通过"的标志,无限的喜悦。我学会了设计,理解了测试驱动开发,并且写测试代码不在烦恼,而是如此的简单,"设计完后就马上去构思测试代码,如果觉得测试代码复杂,又回来修改设计,直到交互都简单为止",这成为我现在的一种习惯。学会这些的同时我又拿到了项目Money,真是爽呀!
     
  经历过这些,我的领会是:在做单元测试之前,你必须要学会设计。设计原则和设计模式是你需要要去掌握和理解的,要让自己在做设计的时候,不会去想"我是否应该用哪种模式",而已灵活运用,根据具体的情况去做,因为你要做到"无剑胜有胜"!
     只有简单的东西才容易写,容易测试。代码变的简单,单元测试同样会变的简单。所以其中最关键的就是你如何将复杂的东西简化。虽然谁都知道这个道理,但是要真正做到还是很不容易的。需要理解,需要实践,需要时间去积累...
     
  这是我做单元测试,并学会测试驱动开发的一个过程,现在虽然自己还是一只"小鸟",但是我可以让代码看上去简单,有了一大堆测试代码的保证,降低了变更的风险。

     工作还在继续,还向着新的目标前进......


   这些就是我的个人经历,希望对于想做单元测试,但处于不知所措的朋友有个借鉴的作用。
  "测试驱动开发",我要让你我的距离变的更近,更近!

写完了,大家可以拍砖了!!!