测试驱动开发
什么是TDD
定义
一种不同于传统软件开发流程的新型的开发方法。他要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简介可用和高质量的代码,并加速开发过程。
出处
测试驱动开发出自极限编程(Extreme Programming,XP)
个人开发者的实践
结对编程(Pair programming)
测试驱动开发(Testing-Driven Development)
重构(Refactoring)
简单设计(Simple Design)
团队层面的实践
代码集体所有权(Collective Code Ownership)
编码规范(Code Standards)
系统隐喻(System Metaphor)
持续集成(Continuous Integration)
可持续的开发节奏(sustainable pace)
项目交付层面的实践
小型发布(Small Release)
客户测试(Customer Tests)
团队协作(Whole Team)
规划策略(The Planning Game)
广义与狭义的TDD
TDD有广义和狭义之分
狭义的TDD: UTDD(Unit Test Driven Development)
广义的TDD: ATDD(Acceptance Test Driven Development), 包括BDD(Behavior Driven Development)和 Consumer-Driven Contracts Development 等。
TDD的三层含义
Test-Driven Development,测试驱动开发
Task-Driven Development,任务驱动开发,要对问题进行分析并进行任务分解
Test-Driven Design,测试保护下的设计改善。TDD 并不能直接提高设计能力,它只是给你更多机会和保障去改善设计
为什么要TDD
传统的编码方式
需求分析,想不清楚细节,管他呢,先开始写
发现需求细节不明确,去跟业务人员确认
确认好几次终于写完所有逻辑
运行起来测试一下,靠,果然不工作,调试
调试好久终于工作了
转测试,QA 测出 bug,debug, 打补丁
终于,代码可以工作了
一看代码烂的像坨屎,不敢动,动了还得手工测试,还得让 QA 测试,还得加班…
TDD编码方式
先分解任务,分离关注点
列Example,用实例化需求,澄清需求细节
写测试,只关注需求,程序的输入输出,不关心中间过程
写实现,不考虑别的需求,用最简单的方式满足当前这个小需求即可
重构,用手法消除代码里的坏味道
写完,手动测试一下,基本没什么问题,有问题补个用例,修复
转测试,小问题,补用例,修复
代码整洁且用例齐全,信心满满地提交
TDD的好处
效率更高
提前确认需求,减少开发中的中断和等待
小步快走,节省调试时间
质量有保证
高测试覆盖率
自动回归测试
如何TDD
TDD的基本流程是:
快速新增一个测试用例
运行所有的测试(有时只需要运行一个或一部分),发现新增的测试不通过
做一些小小的改动,尽快地让测试程序可运行,为此可以在程序中使用一些不合情理的方法
运行所有的测试,并且全部通过
重构代码,以消除重复设计,优化设计结构
注意事项
合理拆分任务
TDD之前要拆分任务,把一个大需求拆成多个小需求,也可以拆出多个函数来。
有效的单元测试
好的单元测试应该符合几条原则:
简单,只测试一个需求
符合 Given-When-Then 格式
速度快
包含断言
可以重复执行
写刚好的实现
专注当前需求,不要把其他需求也实现了,不这样会破坏节奏感,实现的时候要小步快走。
重构
了解什么是
Clean Code
,要看得出代码的Smell
,用合适的「手法」消除 Smell。没有及时重构,等想要重构时已经难以下手了。基础设施
对于特定技术栈,把单元测试基础设施搭建好,写测试时就可以专注在测试用例上。
FAQ
明明知道测试会失败,为什么还要运行一下?
程序并不只有成功和失败两种情况,成功只有一种,然而,失败有无数多种,运行测试才能保证当前的失败是你期望的失败。
小步好,但真的要小步到这个程度吗?
练习过程中应该尽量小步;实际工作中可以先大步,遇到问题再切换为小步
测试覆盖率多少合适?
开始学习时尽量追求100%以分辨什么样的测试好写,什么不好写