Test-Driven Development By Example
TDD 所追求的目标:代码整洁可用(clean code that works)
---Ron Jeffries
TDD 好处:
1,它让软件开发小组成员之间相互信赖;
2,这样的代码写起来感觉很好。
TDD开发中:
1,只有自动测试失败时,我们才重写代码;
2,消除重复设计,优化设计结构;
开发工程中经历的阶段:(TDD口号)
1,不可运行,写一个不能工作的测试程序;(RED)
2,可以运行,尽快让这个测试程序工作;(GREEN)
3,重构,消除重复,优化设计结构;(BLUE)
第一部分,资金实例
TDD过程:
1,快速增加一个测试;
2,运行所有测试,发现最新的测试不通过;
3,做一些小小的改动;
4,运行所有测试,全部通过;
5,重构代码,消除重复设计,优化设计结构。
第1章,多币种资金
讲了一个问题,TDD步子要小,特别是不熟练的情况下,这个道理应该和达芬奇画鸡蛋类似吧,当鸡蛋画的相当熟练了之后,就能运用自如了。
2,变质的对象
对象改变了,测试失败。
3,一切均等
实现了对象值相等的判断
4,私有性
把对象中的参数私有化
12,加法,最后的部分
13,完成预期目标
在消除所有的重复设计之前,不能算完成。无论何时当我们需要显示地判定是哪种类才能进行下一步工作时,都要使用多态来代替。
14,变化
15,混合货币
16,抽象,最后的工作
17,资金实例回顾
测试驱动开发可以被用做一种力争完美的方法,但是其最有效的用途不在于此。项目中经常改动的部分应该是绝对坚实的,因此你才能自信地进行每日的修改。
有时你认为测试不会通过的,但却通过了,这个时候要去找出原因。我在项目中就遇到过这样的问题,是因为有一部分没有测试覆盖到,所有我就立马加上一个测试,然后再跑测试的时候就没有通过,就继续修改代码。
JUnit的用法
作者在写Money代码的时候,点了Junit的测试运行按钮125次,大概每分钟就运行一次测试。小步前进,频繁测试。
测试驱动开发的过程:(RED-GREEN-REFACTOR)
1,加入一个小的测试;
2,运行所有测试,运行失败;
3,适当修改;
4,运行测试且成功;
5,重构,消除重复设计,优化设计结构
单元测试不包括:性能测试,压力测试,可用性测试
第二部分 xUnit 实例
第18章,步入xUnit
第19章,设置表格
常见模式:
1,安排(Arrange):创建一些对象
2,行动(Act):激活它们
3,断言(Assert):检查结果
第20章,后期整理
第21章,计数
第22章,失败处理
总结:
1,使我们的一个小规模测试通过;
2,再次引入大规模测试;
3,大规模测试很快运行通过;
4,潜在问题,先记录在计划清单上。
第23章,如何组成一组测试
第24章,xUnit回顾
第三部分,测试驱动开发的模式
第25章,测试驱动开发模式
没有一个软件工程师会在没有测试的情况下公开甚至是最微小的改动,那些极其自信或极其毛糙的工程师除外。
你感受到的压力越大,你所做的测试就越少。你做的测试越少,你将犯的错误就越多。你犯的错误越多,你感受到的压力就越大。如此循环往复。如果采用自动化测试,那么当我感觉到压力的时候,我就会运行测试程序。我越是感到紧张,越是更多地运行测试。运行测试马上会给我一种良好的感觉,而且会减少我出错的次数,继而减少我所感受到的压力。
测试列表 - Test List:
在开始写测试之前,写一个包含所有你认为必须要编写的测试的清单。
测试优先 - Test First
在编写要被测试的代码之前编写测试。如果我们先进行测试,我们的压力就会减小,这样使得我们更乐意去进行测试。无论如何,测试应该处于一种良性循环当中,否则当压力增加到足够大的时候,测试将被抛弃。
断言优先 - Assert First
试着一开始就编写断言。
1,从我们对最终系统的描述开始构建一个系统;
2,从我们希望最终代码能够通过的测试开始编写一项功能;
3,从测试完成时能够通过的断言开始写一个测试。
当你在写一个测试的时候,你是在同时解决好几个问题,即使你不在需要考虑具体的实现。
1,这一功能性属于哪一部分呢?是通过修改现有方法得到,还是在现有类中构造一个新的方法?或者是在一个新的地方来实现现有的方法?或是实现一个新的类来得到?
2,名字应该怎么起呢?
3,你怎样去检查结果的正确性?
4,什么是正确的结果?
5,这个测试是否需要其他的测试?
测试数据 - Test Data
使用容易让人理解的数据。你是在给大家写测试。不要为了编排数据而编排数据。
显然数据 - Evident Data
要写能让人很容易看懂的测试数据。不要在代码中直接使用魔法数。
第26章,不可运行状态模式
一步测试 - One Step Test
选择那个具有指导意义而且你有把握实现的测试。
启动测试 - Starter Test
从测试某个实质上不做任何工作的操作开始。
说明测试 - Explanation Test
利用测试来请求及提供说明解释。
学习测试 - Learning Test
通过写测试来验证自己对某个API的理解是否正确。
回归测试 - Regression Test
第27章,测试模式
1,子测试 - Child Test
可以写一些能够代表部分大的测试例程的小测试例程,先让小测试运行通过,然后再处理大的测试例程。
2,模拟对象 - Mock Object
在测试中经常会Mock一些对象来达到测试的目的,好处第一是简单,第二是可以在不依赖其他环境的条件下跑测试。
3,自分流 - Self Shunt
第28章,可运行模式
三角法 - Triangulation
当你有两个或者两个以上的例子是,你才能进行抽象
第29章,xUnit模式
1,断言 - Assertion
2,固定设施 - Fixture
setUp()
3,外部固定设置 - External Fixture
tearDown(), tearDown()总是被调用,除非setUp()失败了。
4,测试方法 - Test Method
5,异常测试 - Exception Test
第30章,设计模式
空对象
模板方法
第31章,重构
重构可以在各种规模层次上进行:
1,如果两个循环结构类似,通过使其完全一致,然后将二者合并;
2,一个判定语句的两个分支类似,通过使其完全一致,然后去掉这个条件判定
3,两个方法类似,通过使其完全一致,然后去掉其中一个方法。
4,如果两个类类似,通过使其完全一致,然后去掉其中一个。
第32章,掌握TDD
步伐应该有多大?
应该测试:
1,条件部分
2,循环部分
3,操作部分
4,多态性
总结:
看完这本书,简单的总结一下吧。最近这一个月的时间,也正好参加公司OO Bootcamp 的培训,培训里面也是用TDD的方式进行开发的,所以这里总结的不一定都是看完这边书的感受,也有一些是培训中的,主要还是谈一下TDD。
TDD 给我印象最深刻,也是最近听到比较多的一句话是:小步前进,频繁测试。记得第一节课参加培训的时候,老师要我们三分钟写一个最简单的Unit Test,结果我们很多人没有完成,然后讲课的老师用四十多秒就从打开idea工具开始到写好一个能运行通过的测试用例。到现在,我们一起培训的同事,都能比较快的完成Unit Test的实现。
TDD和以前的开发模式有什么区别呢?
先简单说下以前我和大部分人是怎么开始工作的。首先,我们会有一个Story,这个Story就是针对一个Requirement,然后我们会study requirement,然后开始做一些简单的分析和设计,然后开始实现,实现完自己会做一些测试,然后给QA showcase。就交给QA测试了,没问题了,就OK了。这样有个什么坏处呢?根据项目经验,这样实现的功能给QA showcase或者产品交付的时候经常会发现跟需求有一些差别,需要返工修改,可能还会多次返工修改。因为很多时候,我们开发人员,还没有彻底想清楚需求,就急于去实现功能了。还有一个坏处就是,我们经常一下子就想的很远,然后感觉有很多困难,实现的时候觉得很苦恼。
然后说下TDD,TDD全称Test Driven Development,中文就是测试驱动开发。在最近的培训中,以及这本书里面提到的,拿到story拿到requirement之后,我们首先会分析 Requirement, 然后整理Tasking,就是这个Requirement有哪些,或者说可以分成哪些小部分。整理好Tasking之后,针对每个 Tasking 开始写Unit Test,刚开始写的Unit Test是还没有实现代码的,这个时候运行测试,测试很明显挂了,我们称为Red,红了之后,我们就要开始写实现代码,写实现代码的目的很简单,就是让测试通过,并不需要考虑太长远的东西,也不要去过度设计,画蛇添足。测试通过了之后,我们称为Green。这个时候,要看一下自己写的实现代码是否有bad smell 坏味道,也就是代码是否整洁,如果存在坏味道,就要去重构你写的代码,这个时候我们称为Blue。这三个颜色就是TDD 的三顶帽子。TDD 有什么好处?1,我们先通过拆分requirement ,拆分成较小的Tasking,可以比较好的理解requirement,不容易跑偏;2,把大目标分成小目标,更容易实现;3,通过Unit Test来驱动我们的实现代码,会觉得更轻松,书中也提到了,写Unit Test的时候,其实已经想了很多事情了;4,不容易出现过度设计,每一步实现都是紧贴Tasking;5,代码质量更有保证,更容易,更放心对代码进行重构;6,实现代码都是被Driven出来的,这样是可以更快速的实现代码,感觉就好像有鞭子在后面打一样。这里我也想引用一下,培训时候老师说过的一个过程:Client -> Requirements -> Tasking -> Unit Test -> Development。每一步都是被Driven出来的。
还有很多好处,很多细节,我也不好用语言表达。希望大家可以用心去尝试,去体会一下这个过程。可以更好的感受到TDD所带来的好处。