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中的位置,以及它如何与结对编程协同工作。

TDD与敏捷开发关系图 Scrum 框架 Sprint Planning 用户故事 → 验收条件 → 测试用例 Daily Standup 关注测试状态,而非进度汇报 Sprint Review 演示通过测试的功能增量 Sprint Retrospective 回顾TDD实践,改进测试策略 极限编程 (XP) 实践 TDD (测试驱动开发) 红 → 绿 → 重构 循环 简单设计 重构 持续集成 集体代码所有权 结对编程 驾驶员 + 导航员,乒乓模式 协同 TDD 是敏捷实践的“质量引擎”

实际案例:一个Sprint的TDD实践

最后分享一个我亲身经历的真实案例。团队在做一个支付系统的Sprint,用户故事是“支持信用卡支付”。

第一天(Sprint Planning):

  • 我们和PO一起把验收条件列出来:金额正确、卡号校验、超时处理、失败重试
  • 每个验收条件对应一个测试用例,写在白板上

第二天到第四天(开发阶段):

  • 我和搭档采用结对编程+TDD的方式
  • 我先写一个测试:testPaymentWithValidCard(),预期返回成功
  • 搭档写实现代码,让测试通过
  • 然后搭档写下一个测试:testPaymentWithInvalidCardNumber(),我来实现
  • 就这样交替进行,每个测试都很小,几分钟就能完成一个循环

第五天(Sprint Review):

  • 我们演示了所有测试通过的支付功能
  • PO现场提了一个新场景:“如果网络超时怎么办?”
  • 我们当场写了一个测试,然后修改代码——10分钟搞定

关键收获:因为测试覆盖了所有边界情况,我们敢在Review现场改代码。这就是TDD带来的信心。

好了,关于TDD与敏捷开发的关系,我就聊到这里。记住一句话:TDD不是银弹,但它能让Scrum和XP真正落地。下次你在Sprint里觉得进度失控的时候,不妨试试从写测试开始。


公众号:蓝海资料掘金营,微信deep3321