测试驱动开发初体验
- Java
- 2020-04-30
- 104热度
- 0评论
导航
1 TDD 的价值
我们对新增代码的单元测试覆盖率有明确要求,不达标的代码是不能进主分支的。因此我们需要专门花时间写单元测试。
正常情况,我们是先写功能代码,最后补单元测试。很容易遇到如下问题:
- 已经写好的功能代码,耦合度较高,写 UT 很艰难。
- 写 UT 耗时长,易出错,基本离不开 Powermock;
- 到达一定水平后(例如 60%),UT 覆盖率很难再往上提。
如果采用 TDD 的方式,有以下优点:
- 第一次写出的功能代码,就是“易于测试”的代码,耦合度较低,UT 写起来方便快捷,较少用到 Powermock;
- 强迫自己先想清楚需求(接口应该实现什么功能),再编码实现,减少返工几率;
- UT 覆盖率很高,一次性达到要求,不需要后期花时间补单元测试;
- 为以后做重构提供可靠的保障。
2 什么是 TDD
TDD,即测试驱动开发。是敏捷开发在编码层面的一种具体实践。
2.1 澄清一些常见误解
误解 1:TDD 的重点在于写单元测试
TDD 是一种开发技术,而不是一种测试技术。
误解 2:TDD 很费时间,是一种高质量但低效的实践
如果 TDD 很费时间,实战价值不大,它就不应该是一种行之有效的敏捷方法。在 UT 覆盖率必须达标的前提下,TDD 比常规的先开发后写 UT 的方式更快。
至于开发效率,有很多影响因素,从之后的例子中可以看出,凭借对工具和方法的熟练使用,TDD 也可以很快。
误解 3:TDD 需要先把测试类写完整,才能写功能代码
这是典型的瀑布思维:先定义完整的需求,然后一次性实现。
实际的 TDD 不是这样的。先写一小部分测试代码,然后写功能代码。可以 work 之后,接着写测试代码。小步快跑。具体用法后面详细介绍。
误解 4:可以先写一个功能类,再写一个测试类;或者先写一半功能类,再写一半测试类
虽然也是小步快跑,但不是测试驱动。
2.2 TDD 的节奏
- 写一个失败的测试;
- 写最少的功能代码,让测试通过;
- 重构,消除重复代码,改进设计;
- 再写一个失败的测试,循环往复。
理论上,每一次小型增量迭代结束后,都得到一个可以 work 的,覆盖率 100% 的系统。
2.3 TDD 的原则
- 没有失败的测试就不能写代码;
- 只写恰好让测试通过的代码(在不超过1分钟的时间内,让一个失败的测试通过)。
3 TDD 实战体验:FizzBuzz
下面,通过一个实际的例子,来感受一下 TDD 的运用方式。
3.1 FizzBuzz 开发需求
题目描述
写一个程序,打印出从1到100的数字,将其中3的倍数替换成“Fizz”,5的倍数替换成“Buzz”。既能被3整除、又能被5整除的数则替换成“FizzBuzz”。
样例输出:
验收要求
- 10min 内完成功能(有一些同学在长期练习后可以做到 2 分钟内完成)
- UT 覆盖率 100%
- 代码尽量符合规范,没有重复代码
乍一看,这个需求很简单。但是考虑到 UT 和代码质量,就变得很难。
3.2 实操
我们可以打开计时器,正儿八经地做一下这道题目。看能做到什么程度,过程中有没有磕磕碰碰。
(此处省略一万字)
3.3 课代表示范
[evp_embed_video url="http://jiuyeban-public.jikexueyuan.com/attachment/2019/0514/folder/rD3pPDuG7xF3Ie07fcTXQvFh8HaoFNv5ID0qcSBA.mov"]