28、TDD与敏捷开发:TDD在Scrum和极限编程中的角色,与结对编程的结合
聊到TDD,就不能不提敏捷开发。说实话,我见过太多团队把TDD当成一个孤立的技术实践,结果搞得很痛苦。其实TDD真正的威力,是在敏捷的土壤里才能完全释放出来的。今天我们就来聊聊TDD在Scrum和极限编程(XP)中到底扮演什么角色,以及它和结对编程怎么擦出火花。
TDD与Scrum:节奏的共鸣
Scrum的核心是迭代,也就是Sprint。每个Sprint通常2-4周,团队要交付一个可用的产品增量。TDD在这里扮演什么角色?我个人的理解是——TDD是Scrum节奏的“节拍器”。
你想想看,一个Sprint开始的时候,我们会开Sprint Planning,确定这个Sprint要完成哪些用户故事。每个用户故事,说白了就是一组验收条件。TDD正好能把这些验收条件转化成测试用例。
核心观点:在Scrum中,TDD不是额外的工作,而是把“需求”翻译成“可执行的测试”的过程。
我在项目中遇到过这样的情况:团队在Sprint中期发现需求理解有偏差,导致返工。后来我们强制要求:每个用户故事在开发前,必须先写出验收测试。这样一来,测试就是需求,需求就是测试。任何歧义在写测试的时候就会暴露出来,而不是等到代码写完了才发现。
TDD与极限编程(XP):天生的搭档
极限编程(XP)有12个核心实践,TDD是其中之一。但我觉得,TDD其实是XP其他实践的“粘合剂”。
| XP实践 | TDD如何支撑 | 我的经验 |
|---|---|---|
| 简单设计 | TDD强制你只写通过测试所需的最少代码 | 我曾经因为过度设计被测试“打脸”,后来老实了 |
| 重构 | 测试套件就是重构的安全网 | 没有TDD的重构,就像走钢丝不带保险绳 |
| 持续集成 | 每次提交都跑测试,保证代码不坏 | 我见过CI流水线里测试全红,团队还照常发布——那叫自欺欺人 |
| 集体代码所有权 | 测试让任何人都有信心修改别人的代码 | 嗯,这一点在团队里推行起来其实挺难的 |
说白了,XP的核心是“拥抱变化”。而TDD给了你拥抱变化的底气——因为你知道,改错了测试会告诉你。
TDD与结对编程:1+1 > 2
结对编程,就是两个人坐在一台电脑前写代码。一个当“驾驶员”(写代码),一个当“导航员”(思考策略)。TDD和结对编程结合,效果出奇的好。
为什么会这样?我分析过原因:
- 红-绿-重构的节奏天然适合结对:一个人写测试(红),另一个人写实现代码让它变绿。角色可以轮换,效率很高。
- 测试设计需要讨论:写测试用例的时候,两个人可以讨论边界条件、异常情况。一个人容易漏掉的东西,两个人一起想就全面多了。
- 减少“钻牛角尖”:我自己写代码时经常陷入一个死胡同出不来。结对的时候,导航员会提醒你:“先写测试,别想太多。”
我的建议:结对编程时,可以尝试“乒乓模式”。A写一个失败的测试,B写代码让它通过,然后B写下一个失败的测试,A来通过。这样交替进行,节奏感很强。
避坑指南:我曾经踩过的坑
讲几个我亲身经历的问题,希望能帮你少走弯路。
坑1:把TDD当成“测试先行”就完事了
我曾经以为只要先写测试就是TDD。结果测试写得又大又复杂,根本跑不起来。后来才明白,TDD的核心是小步快跑——每次只写一个很小的测试,然后让它通过。测试太大,步子就迈不开了。
坑2:结对编程时两个人都不说话
我见过最尴尬的场景:两个人坐在一起,各写各的,全程零交流。那还不如分开写呢。结对编程的核心是持续对话。导航员要不断问:“下一个测试是什么?”“这个实现够简单吗?”
坑3:Scrum的Daily Standup变成了“汇报进度”
其实Daily Standup应该关注的是:测试通过了吗?如果测试没通过,那进度就是假的。我后来在团队里推行“测试驱动站会”——每个人先汇报测试状态,再说进度。效果立竿见影。
一张图看懂TDD与敏捷的关系
下面这张图展示了TDD在Scrum和XP中的位置,以及它如何与结对编程协同工作。
实际案例:一个Sprint的TDD实践
最后分享一个我亲身经历的真实案例。团队在做一个支付系统的Sprint,用户故事是“支持信用卡支付”。
第一天(Sprint Planning):
- 我们和PO一起把验收条件列出来:金额正确、卡号校验、超时处理、失败重试
- 每个验收条件对应一个测试用例,写在白板上
第二天到第四天(开发阶段):
- 我和搭档采用结对编程+TDD的方式
- 我先写一个测试:
testPaymentWithValidCard(),预期返回成功 - 搭档写实现代码,让测试通过
- 然后搭档写下一个测试:
testPaymentWithInvalidCardNumber(),我来实现 - 就这样交替进行,每个测试都很小,几分钟就能完成一个循环
第五天(Sprint Review):
- 我们演示了所有测试通过的支付功能
- PO现场提了一个新场景:“如果网络超时怎么办?”
- 我们当场写了一个测试,然后修改代码——10分钟搞定
关键收获:因为测试覆盖了所有边界情况,我们敢在Review现场改代码。这就是TDD带来的信心。
好了,关于TDD与敏捷开发的关系,我就聊到这里。记住一句话:TDD不是银弹,但它能让Scrum和XP真正落地。下次你在Sprint里觉得进度失控的时候,不妨试试从写测试开始。