关于“测试驱动开发”的问答

谢谢大家给了我很多值得思考的问题,下面是我对这些问题的一个回答,希望能有所帮助。最关键的,还是亲手去试一次。
1、如何保证测试代码的正确性?
这是一个很实际,也是很常见的问题。我想这个问题并没有一个非常完美的答案,其实从理论上探讨倒是更像“鸡生蛋,蛋生鸡”的问题。首先要确定的是我们不可能为测试代码再写一个测试代码。其次这个问题的解决可以通过缩小TDD的粒度来解决这个问题。在Kent Beck的书上有专门的讨论粒度的地方,基本上应该先写最简单的代码,保证测试的正确性;然后再通过重构和测试保证代码。

2、测试的粒度应该多大?
没有固定的答案,如果对自己很自信,粒度就可以粗一些;如果遇到错误或者问题比较棘手,粒度就可以小一些。

3、对GUI层开发应用TDD是否利大于弊?
就现在的GUI层测试的工作量来看,如果GUI超过10个(我个人的经验和估算),对GUI的TDD就非常有价值。否则,从成本上考虑就不太合适。
但是随着TDD工具的改进,GUI TDD的成本开始下降,我想也许不久以后,对少量的GUI进行TDD也不会太复杂了。
一个值得关注的工具就是NUnitForm, 通过他不但可以用传统的方式写代码来驱动GUI测试,还可以用录制脚本的方式自动生成TDD的代码。

4、如何在没有TDD习惯和思想的团队推行TDD?
With most men,unbelief in one thing springs from blind belief in another.—Georg Christoph Lichtenberg
所以,在有一两个有TDD经验的人的辅助下,在实际项目中使用TDD进行开发,让每个人都亲身感受一下。我个人的感觉是接受起来并没有当然,team lead必须根据具体情况,根据团队的特点,成员的性格,在项目开始的磨合阶段对TDD的形式作一些修正。当然,最关键的还是两点:每个人有一个开放的心态;以及团队要足够的灵活和健康的讨论氛围。

5、如何保证需求(用户视图)和测试代码(TDD开发者视图)的完全映射及同步?
也即同步用户和TDD开发者的项目成功标准。
这个问题就不仅是TDD的问题了,各种软件开发理论都需要回答这个问题。 所以这个问题的答案取决于不同的理论,XP的方式是通过一个User Story驱动多个Test Case。

我昨天晚上回去的时候想了想,下面是我的一些想法,供参考:
1、我感觉这个讲座重点,应该是分析(包括使用代码)我们常用的“先设计,再开发测试的模式”与“测试先行,设计和重构断后的模式”的优缺点,以及他们可能应用的范围,在哪些方面这些模式又有局限,我想不可能有一个万能的模式去解决所有的问题,不论是第一种模式还是第二种模式都会有适用范围的。一种模式完全取代另一种模式的可能性比较小。
2、就我的水平和眼界而言,或者说我的习惯和思维方式而言,我喜欢“先设计,再开发测试的模式”,直到把问题想清楚了再去写代码。对于我这种人,如果要求使用“测试先行,设计和重构断后的模式”,至少应该说服我,这种新的模式比我现在使用的模式好处在什么地方,而且是比较大的优点,否则我不会去改我的习惯,或者没有动力去改变现状。尤其是演示代码的时候,不断的重构,推上,拉下,我回去的时候能够回忆起来的就是一个“乱”字,那我就会本能的不去使用这种新的模式。
3、NUnit测试很重要,这一点估计没有人会反对(Gary,shut up!:-) )。但是到底有多重要,是一个手段,还是到了整个项目驱动器的地位,应该视情况而言吧。
4、可以谈谈NUnit的不足的地方。
5、昨天我和Gary在讲座上说了一些跑题的话,撇开礼貌问题不谈,至少说明讲座没有能够说服我们这种还在使用第一种模式的人;或者讲座不太紧凑,没有抓住听众,吸引听众,引起听众的思考。当然要引起思考很难,尤其是我这种从不思考的听众。又跑题了。
我这个周末稍微想了一下,觉得也许有可能把Design-first的“制度性和确定性”与TDD的“安全性”作一个结合,这个周二我想试验一下这个想法,希望到时候能听到你们的反馈。另外,我还把PPT重新写了一编,加入了更多思考和反馈的内容,但是时间不知道是否足够。这也是为什么每次正式之前有一个预演的原因。
就使用范围来说,我有一个比较极端的观点就是超过1个人2个月的项目,都应该使用TDD。当然,正如我在一开始的时候提到的,TDD更应该成为一种思维方式,而不仅仅限于一种技能。
我觉得Test Driving是一种很好的设计与开发方式,至少是在一些场合来使用是非常适合的。伟大的软件都不设计出来的,而是一点儿一点儿做出来,一次一次的代替,一次一次的反复,是理想与现实的不断冲突和妥协的结果,这是软件开发的现实。Test Driving正是用这样一种面对现实的态度来设计与开发的,是现实主义的;而严密的设计之后,再编程的方式,我认为是理想主义,但理想在现实面前往往都被击得粉碎,我想大家也有同感吧。现实主义和理想主义都有它们各自的用武之地,但现实主义适用于更多的场合。
我觉得Test Driving适用地方:
1 抽象的底层代码,基本的需求是稳定,可以反复的refactor;
2 业务逻辑层的代码,可以在变更后,知道所有业务功能还能不能工作,一方面能refactor,另一方面能在一定程度抵抗需求的变化;
Test Driving不适用的地方:
1 已经非常熟悉的领域,先设计再开发就是很好的方法,直接做好就成了
2 需求很不稳定的业务逻辑层的代码,写了的测试,会因变更的需求,变得无用,成为浪费。
3 界面程序,但这是因为现在的Nunit还不够强大
我想牛刚上面的论述我基本上同意,但是也许是演示的问题,我的总体感觉是大家觉得开发过程非常混乱。其实就我当时的思路是非常清楚的。对于不适用的2,我首先同意有一些测试代码会因为需求变化而没有用了,但是从另外一个角度看,如果需求变动频繁到feature被cut掉的话,说明需求、结构变化也很频繁,这种情况倒是TDD能真正显示作用的。
我个人觉得TDD中间最应该注意的是测试代码本身的正确性和整洁的问题,Test code能否做到Clean和Work非常重要。TDD使用不好的情况下,测试代码很brittle,结果需求一改变,很多测试代码跟着需要改变,给维护测试代码本身也带来了不小的工作量;这就要求测试代码也要不断的refactoring,保证测试的唯一性和有效性。那么,对测试代码的refactoring,由什么机制来保证呢? 有已经有的功能性代码保护,首先确定测试代码是正确的,然后进行重构,如果重构后测试不通过,就说明测试代码出了问题,这里有一个根本原则是绝对不能同时修改功能行代码和测试代码,否则将失去一个正确的参照物。
http://dongxun.mblogger.cn/posts/4848.aspx

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结