TDD 有三层含义
- Test-Driven Development,测试驱动开发。
- Task-Driven Development,任务驱动开发,要对问题进行分析并进行任务分解。
- Test-Driven Design,测试保护下的设计改善。TDD 并不能直接提高设计能力,它只是给你更多机会和保障去改善设计
TDD 编码方式
- 先分解任务,分离关注点(后面有演示)
- 列 Example,用实例化需求,澄清需求细节
- 写测试,只关注需求,程序的输入输出,不关心中间过程
- 写实现,不考虑别的需求,用最简单的方式满足当前这个小需求即可
- 重构,用手法消除代码里的坏味道
- 写完,手动测试一下,基本没什么问题,有问题补个用例,修复
- 转测试,小问题,补用例,修复
- 代码整洁且用例齐全,信心满满地提交
好处
- 只关注需求编写用例,程序的输入输出,不关心中间过程。因为从使用者角度出发的简单设计,也可以更快地适应变化
- 出于易测试和测试独立性的要求,将促使我们实现松耦合的设计,并更多地依赖于接口,提高系统的可扩展性和抗变性
- 可以尽量地避免和尽早地发现错误,极大地降低了后续测试及修复的成本,提高了代码的质量
- 由于用例全面,所以代码的改动产生的任何异常,测试都会立刻通知我们
- 在测试的保护下,不断重构代码,以消除重复设计,优化设计结构,提高了代码的重用性
- 快速的提高了开发效率
如何做好
分离关注点,一次只戴一顶帽子
在我们编程的过程中,有几个关注点:需求,实现,设计。
TDD 给了我们明确的三个步骤,每个步骤关注一个方面。
红:写一个失败的测试,它是对一个小需求的描述,只需要关心输入输出,这个时候根本不用关心如何实现。
绿:专注在用最快的方式实现当前这个小需求,不用关心其他需求,也不要管代码的质量多么惨不忍睹。
重构:既不用思考需求,也没有实现的压力,只需要找出代码中的坏味道,并用一个手法消除它,让代码变成整洁的代码。
注意力控制
人的注意力既可以主动控制,也会被被动吸引。注意力来回切换的话,就会消耗更多精力,思考也会不那么完整。
使用 TDD 开发,我们要主动去控制注意力,写测试的时候,发现一个类没有定义,IDE 提示编译错误,这时候你如果去创建这个类,你的注意力就不在需求上了,已经切换到了实现上,我们应该专注地写完这个测试,思考它是否表达了需求,确定无误后再开始去消除编译错误.
自己的实例
有一个需要计算清结算偏移时间的需求,简单分析并明确需求
大概有如下的用例:
- 固定自然日T+N,如果计算后日期为节假日则取节假日后第1个工作日
- 按周 每周1-5,下周第一个工作日清算,每周6-7,下周第二个工作日清算
- 按周 每两周清算一次,在下两周的第1个自然日清偿
- 按月 每个月清算一次,在下个月第2个自然日清偿
开始编写测试用例
(当天,日周期,频率2,延迟1天) -> 当天+2后的第一个工作日
(周1,周周期,频率1,延迟1天) -> 下周第一个工作日
(周6,周周期,频率1,延迟2天) -> 下周第二个工作日
(周日,周周期,频率2,延迟2天) -> 下周第二个工作日
(1号,月周期,频率1,延迟1天) -> 下月第一个工作日
(31号,月周期,频率1,延迟1天) -> 下月后第一个工作日
(2月28号,月周期,频率1,延迟1天) ->3月第一个工作日
(15号,月周期,频率2,延迟2天) -> 下两月后第二个工作日
编写接口:
calculate(Date triggerTime,String type,String frequency,int day)
编写实现:
用switch计算等等,很简单快速的
测试,运行,通过.
消除冗余代码,使用抽象替换调switch。然后再写测试用例,在运行测试。
继续优化里面的细节,也是先写用例,在继续运行。如此重复,并不断用敏捷开发的一些原则和技巧进行不断的优化甚至重构.
后来发现calculate接口参数可以通过db拿到,只通过传入一个规则Id就可以了。
调整测试用例,最终的接口如下
fetchClearingExpectDate(Date triggergTime,String ruleCode,HolidayModel holidayModel);
这样,最终交付的时候,功能基本都是可测试的,也不会出现代码写到最后一运行需要大的改动,如此以往提供了开发的效率。
网友评论