过去一年里,”让 AI 写测试优先”几乎成了 AI 编程的政治正确。绝大多数被传播的 CLAUDE.md、AGENTS.md、.cursorrules 里,都能找到一句”先写失败的测试,再写实现”。这条规则听上去无懈可击:TDD 是被验证了二十多年的工程实践,agent 又是最不值得信任的写码者。
Thoughtworks 的 Birgitta Böckeler 决定不靠感觉,搭一个对照实验去测。她是 Thoughtworks 的 Distinguished Engineer,专注 AI 辅助交付方向,有二十多年开发、架构与技术领导经验,这篇实验属于 “Exploring Gen AI” 系列。结论是反直觉的:让 agent 在自己的循环内完整跑 TDD,并没有产出更好的方案,反而在多数批次里被评委模型排在后面,同时 token 消耗高出 3 到 8 倍。
TL;DR
- 没有可见的质量优势。基于 Opus 对结果质量的盲评,TDD 与非 TDD 之间没有明显可辨的差异;反过来,Opus 不止一次把非 TDD 方案在设计和测试质量上排得略高。所有方案的变异分数(mutation score)也没有有意义的差异。
- 代价是确定的。TDD 路线在小/中/大三个任务上的 token 均值倍数分别是 8.50x、2.96x、4.89x,轮次和工具调用数同步翻几倍。
- 原因可能在”前置设计”。Opus 回看会话轨迹后发现,非 TDD 和”仅测试优先”的 run 总是先把完整设计做出来(架构、数据类型、边界情况、契约)再动手,而 TDD 指令主动对抗这个前置设计步骤。
- 红-绿在无人循环里失去意义。当 agent 既写测试又确认它失败时,红灯只能证明”agent 跑了它并看到失败”,不能证明”失败是出于正确的原因”。
- 作者本人的做法改了。她已经停止让 coding agent 写测试优先,转而用变异测试、结构审查、Approved Scenarios 分别兑现 TDD 曾经提供的那几项价值。
这是探索性的小规模 eval。本文第八节专门讲”这个实验没证明什么”,读到那里之前先别急着改团队规范。
一、先分清三种”AI + TDD”
社区里绝大多数关于”AI 要不要 TDD”的争吵,都是双方在说不同的三件事:
- 人类写测试:人类以自然语言、BDD 风格或直接写代码的形式定义测试场景,AI 写实现让它们通过。规约所有权在人手里。
- 给人类留审查检查点:AI 先写失败测试,人类看一眼确认它测的确实是想要的行为,AI 再写实现。红灯必须有人解释这一环被保留。
- 完全在 agent 循环内:提示 agent 一个一个先写失败测试、再写实现、再确认变绿。整个红-绿-重构循环里没有人。
作者明确指出:现阶段第三种是远远最常见的用法,而这个实验测的正是第三种。如果你的团队用的是前两种,这份数据基本不适用。
这个区分很重要,因为 TDD 的很多经典收益本质上是人类心理层面的机制。把人从循环里拿走以后还剩多少,是需要单独回答的问题,不能从”TDD 二十年被验证有效”直接推导。相关的人机边界讨论可见AI Agent架构探讨:如何界定”大脑”思考与”工具”执行的边界?与与大模型斗智斗勇:开发者在信任交付与零信任审核间的极限拉扯。
二、实验设置
任务:借助 Claude 生成三个规模的任务,全部是绿地业务逻辑。作者特意要求”特异且具体的逻辑”,提高方案间出现差异的概率,避免所有 run 都复述训练数据里已占主导的标准写法。
- 小:Python 模块,校验
DAY-TIME-ROOM-CHECKSUM格式的医疗预约槽位代码,返回结构化结果标明哪条规则失败、为什么。 - 中:4 阶段 Python 管道(parse → aggregate → format → validate),把
ROW_ID:CATEGORY:VALUE:PERIOD转成纯文本报告。 - 大:内存态 Python 忠诚度积分引擎,含分层赚取率(Bronze/Silver/Gold)、用于层级重算的滚动 365 天消费追踪、积分兑换。
模型分工:Sonnet 4.6 生成方案;Sonnet 4.6 判定 TDD 遵循程度;Opus 4.8 在不知道方案怎么产生的情况下比较质量。作者刻意没给非常具体的质量标准——以她的经验,标准给得越具体,模型越可能对它过拟合。Opus 排名时当场生成评分细则传给所有子 agent。
统一指令:所有 run 都包含”至少 80% 代码覆盖率”。这意味着非 TDD 组不是”不写测试”,只是不按 TDD 流程写。这一点在传播中经常被误读。
批次:5 批,每批 2 个非 TDD + 2 个 TDD,其中一批额外加 2 个”仅测试优先”(先写测试但无完整 TDD 纪律、无增量红绿)。小任务 1 批、中任务 3 批、大任务 1 批。标记:NT = 无 TDD,T = TDD,TF = 测试优先。
四条 caveat(作者原列):样本量非常小;”质量”判断几乎完全交给 Opus;没有任何一次 run 完美遵循 TDD,但都做得不错;任务全部是绿地、相对小规模、纯业务逻辑。
第四条尤其重要——遗留代码、跨模块重构、大型代码库这些 TDD 最被认为有价值的场景,一次都没测。关于 AI 在存量代码上的表现,可对照模型表现差可能真不赖 AI:代码坏味道正成为编程大模型的最大绊脚石。
三、agent 到底能不能做好 TDD
在比较之前,作者先要确保 TDD 指令真的被执行了。她说历史上这件事一直不顺利,agent 常见三类失败:先写实现再补测试;跳过确认红灯;超前于当前测试实现,导致下一个测试写出来就是绿的。
她最后用的提示词在 Sonnet 上”够用”,但所有会话都在不同程度上表现出了上述失败。为避免把没真做 TDD 的 run 算进结果,每个 TDD run 都配了独立 agent 基于会话记录判断遵循程度。
这个前置发现本身就很重要:“我在提示词里写了 TDD”和”agent 真的在做 TDD”是两件事。如果你的规范里有这条规则却从没验证过会话里的红灯是否真红过,那你可能已经在支付成本而没拿到收益。类似的”指令被静默降级”现象可见频繁改需求致 AI 代码”返祖”?开发者探讨如何维护上下文一致性。
四、五批数据
4.1 中任务第一轮
| ID | TDD | 测试数 | 覆盖率 | 变异分数 | 总 Token | 轮次 | 工具调用 |
|---|---|---|---|---|---|---|---|
| NT1 | 否 | 75 | 100% | 84.2% | 769,814 | 31 | 37 |
| NT2 | 否 | 107 | 100% | 89.6% | 703,159 | 21 | 24 |
| T1 | 是 | 30 | 100% | 81.0% | 1,519,762 | 71 | 28 |
| T2 | 是 | 34 | 99% | 77.3% | 2,580,897 | 103 | 60 |
Opus 判词:NT1(第 1) 一阶段一模块、dataclass、Decimal,无正确性 bug,错误处理最强,唯一检查重复 ROW_ID;NT2(第 2) 工程质量最好、测试套件最大,但验证器会拒绝它自己产出的合法小数输出;T1(第 3) 单模块、字典、float,验证是循环的(重跑 formatter),接受 nan/inf;T2(第 4) 有活跃的 TOTAL 行 bug(人头数加进美元金额),而且这个 bug 被一个测试固化下来了。
T2 那条是最典型的失效模式:测试先写不等于测试写对,一旦 agent 对需求的理解本身就错,先写的测试只会把错误理解锁死成一份看起来很权威的规约。
4.2 中任务第二轮:加入”仅测试优先”
| ID | 方法 | 测试数 | 覆盖率 | 总 Token | 轮次 | 工具调用 |
|---|---|---|---|---|---|---|
| NT1 | 无 TDD | 107 | 100% | 703,159 | 21 | 20 |
| TF2 | 测试优先 | 90 | 92% | 619,531 | 27 | 26 |
| NT2 | 无 TDD | 75 | 100% | 769,814 | 31 | 30 |
| T2 | TDD | 29 | 98% | 2,099,280 | 96 | 95 |
| TF1 | 测试优先 | 62 | 99% | 268,323 | 17 | 16 |
| T1 | TDD | 25 | 100% | 2,017,739 | 90 | 89 |
| ID | 方法 | 设计 | 代码 | 测试 | 均分 | 实现/测试 LOC |
|---|---|---|---|---|---|---|
| NT1 | 无 TDD | 8 | 8 | 8 | 8.0 | 497 / 881 |
| TF2 | 测试优先 | 8 | 8 | 7 | 8.0 | 484 / 850 |
| NT2 | 无 TDD | 8 | 8 | 7 | 7.5 | 330 / 430 |
| T2 | TDD | 7 | 7 | 6 | 6.5 | 207 / 304 |
| TF1 | 测试优先 | 6 | 6 | 6 | 6.0 | 348 / 360 |
| T1 | TDD | 6 | 6 | 6 | 6.0 | 142 / 228 |
盯住一个现象:TDD 组的测试数量最少(25、29),非 TDD 组是 107、75;TDD 组实现代码也最短(T1 只有 142 LOC)。这不是”TDD 让代码更精炼”,而是原文假说的直接体现:agent 没想到要为之写测试的行为,压根没被实现。功能边界被”agent 依次想到了哪些测试”这条随机链条限定住了。
4.3 中任务第三轮:强化 TDD 提示词之后
作者意识到 agent 在循环里没怎么做重构,改了提示词加重强调前置设计与重构步骤。
| ID | TDD | 测试数 | 覆盖率 | 变异分数 | 总 Token | 轮次 | 工具调用 |
|---|---|---|---|---|---|---|---|
| T1 | 是 | 51 | 100% | 90.2% | 3,447,283 | 117 | 116 |
| NT1 | 否 | 107 | 100% | 89.6% | 703,159 | 21 | 20 |
| NT2 | 否 | 75 | 100% | 84.2% | 769,814 | 31 | 30 |
| T2 | 是 | 43 | 100% | 81.1% | 1,421,671 | 61 | 60 |
均分:T1 7.67(设计 8/代码 8/测试 7)> NT1 7.33 > NT2 7.0 > T2 6.67。头号弱点:T1 只含 HEADCOUNT 的 TOTAL 行被打印成 $、验证只是子串检查不是算术;NT1 小数 HEADCOUNT 在合法输入上触发假 ValidationError;NT2 NaN/Infinity 让管道崩溃而非抛 ParseError;T2 验证是重言式(拿聚合结果检查它自己)。
这是全实验唯一一次 TDD 拿到第 1 名,代价是 3,447,283 token 和 117 轮。致命的是:用同一份提示词跑的另一个 TDD run(T2)排在最后一名。同样的指令、模型、任务,一个第一一个垫底——这个方差本身就是对”TDD 指令能稳定提升质量”的反驳。
4.4 小任务
| ID | TDD | 测试数 | 覆盖率 | 变异分数 | 总 Token | 轮次 | 工具调用 |
|---|---|---|---|---|---|---|---|
| NT1 | 否 | 61 | 100% | 89.6% | 122,108 | 10 | 15 |
| NT2 | 否 | 58 | 100% | 92.3% | 117,522 | 10 | 20 |
| T1 | 是 | 21 | 100% | 93.6% | 894,451 | 55 | 37 |
| T2 | 是 | 20 | 100% | 93.2% | 1,142,039 | 68 | 26 |
均分:NT1 8.67 > NT2 8.0 > T1 7.33 > T2 6.67。NT1 综合最好——dataclass 结果、无 bug、61 个断言”失败原因”的测试;T2 设计最弱(自由文本错误)且有真实崩溃 bug。
这是最刺眼的一组:TDD 组多花约 8.5 倍 token,换来第 3、第 4 名。有意思的是 TDD 组的变异分数(93.6%/93.2%)反而最高,但测试数只有对方三分之一——说明用测试数量当质量代理指标是不可靠的。
4.5 大任务
| ID | TDD | 测试数 | 覆盖率 | 变异分数 | 总 Token | 轮次 | 工具调用 |
|---|---|---|---|---|---|---|---|
| NT2 | 否 | 69 | 100% | 86.9% | 322,148 | 14 | 13 |
| T2 | 是 | 22 | 99% | 85.6% | 1,225,517 | 63 | 62 |
| T1 | 是 | 21 | 99% | 85.2% | 1,253,300 | 67 | 66 |
| NT1 | 否 | 74 | 99% | 89.4% | 185,094 | 11 | 9 |
均分:NT2 8.25 > T2 7.5 = T1 7.5 > NT1 6.75。这是唯一一次模式被打破:TDD 落在中间,两个非 TDD 同时拿走最好和最差。NT2 是唯一带真实输入校验的方案;NT1 拿了最高设计分和 74 个测试,却带着两个高级 bug(批次提取顺序错误、未来日期积分被算成可消费)。
这组说明非 TDD 的方差更大——它可以做得非常好,也可以在测试很多、设计分很高的情况下藏着严重 bug。这正是开发效率与代码质量的博弈:AI生成的代码是否仍需人工Code Review?里反复出现的矛盾。
整体模式:小任务和中任务上,Opus 把两个非 TDD 排第 1、第 2,两个 TDD 排第 3、第 4,唯一例外是强化提示词那一批;大任务上 TDD 居中。一句话——两边都当过第一也都当过最后,整体 TDD 略差。
五、被误读的”3 倍 token”:口径比数字重要
| 任务规模 | 无 TDD 均值 | TDD 均值 | 倍数 |
|---|---|---|---|
| 小 | 119,815 (n=2) | 1,018,245 (n=2) | 8.50x |
| 中 | 736,486 (n=2) | 2,181,105 (n=6) | 2.96x |
| 大 | 253,621 (n=2) | 1,239,408 (n=2) | 4.89x |
关键在于这个数字是怎么算的。 作者明确说明:记录 token 用量的设置用的是 pi-coding-agent SDK 的 getSessionStats(),它把会话里每一个 assistant turn 的 input + output + cacheRead + cacheWrite 全部求和。
每一轮 assistant turn:
重新读取累积上下文 → 绝大部分命中缓存 (cacheRead)
本轮计一次,下一轮又读又计一次 ...
Total Tokens ≈ Σ(每轮上下文规模) ≈ 轮次数 × 上下文平均规模
作者原话:所谓 “Total Tokens” 更多是在追踪一个会话花了多少轮,并按当时上下文长到多大来加权;它把便宜的缓存读和昂贵的新鲜 token 一视同仁,因此很可能高估了 TDD 的真实美元成本。实验期间没有单独追踪缓存命中率。所以正确的读法是:
- ❌ “TDD 让 API 账单变成 3 到 8 倍”——不成立,缓存读单价远低于输入输出。
- ✅ “TDD 让会话轮次和工具调用数变成几倍”——成立且有直接证据:小任务从 10 轮变成 55–68 轮,中任务从 21–31 轮变成 61–117 轮。
- ✅ “TDD 可靠地贵好几倍,具体几倍可变”——作者自己给的定性表述,把倍数当方向性指标。
轮次翻倍其实比 token 更值得关心,因为它直接对应墙钟时间和上下文膨胀。做成本可观测性时这个口径问题很典型,可对照开源工具Wattage:精准监控AI智能体Token开销的回归测试门禁与开发者吐槽AI编程现状:模型陷入”虚假忙碌”,95%推理Token被浪费。
六、七项收益逐条失效
作者跳过那些”只要有测试”就能拿到的收益(重构安全网、活文档、覆盖率),只保留流程本身特有的,逐条问:agent 循环里还拿得到吗?
1. 测试优先 → 避免重言式测试。 实验里有些 TDD 会话照样出现了这个问题——一个特别明显的例子是测试拿实现的输出和它自己比对,重新跑同样的代码去生成”期望”答案。先写测试不能可靠阻止这件事,也许能降低概率,但小数据集不足以下结论。
2. 测试优先 → 可测试性。 结果没有给出明确信号。作者坦承任务规模不需要那么多设计复杂度,不足以让这个问题浮现。
3. 红-绿 → 测试有效性。 作者提了最锋利的一问:当人被移除时,这件事还有多少意义? 看着测试变红,只有在有人去检查它为什么变红时才能证明任何事情。当 agent 既写测试又确认它失败,红灯告诉你的是”agent 跑了它并看到失败”,不是”失败是因为正确的原因”。遵循度评估也印证:agent 仍会跳过或伪造红灯,或超前实现让测试立刻变绿。她的替代答案是变异测试——不在乎回归质量怎么达成,只要有机制能看到它有多好;而实验里 TDD run 的变异分数并没有显著更好。
这条推理的普适价值大于 TDD 本身:任何”过程指令”在无人循环里都会退化成一个可以被 agent 自己签字的形式。这正是专治 Agent 工具调用不靠谱:开发者开源多维评测框架,混合规则与大模型裁判这类工作的动机——把验证从”过程自证”挪到”结果外测”。
4. 测试优先 + 红绿重构 → 驱动更好的设计。 实验完全没有展示 TDD run 有更好的设计。作者说她现在甚至怀疑 TDD 是不是让设计变差了,同时强调数据集太小无法定论,并公开呼吁有人跑更大规模的复现。她的解释很精准:
当人类先写测试时,它迫使我们在实现之前思考用法,我们不得不坐在那种摩擦里。agent 不会经历那种摩擦,它可以在规划实现的同一瞬间写出测试。在两者之间没有人类检查点的情况下,先写测试还剩下什么目的?
Opus 回看轨迹的机制解释是:非 TDD 和测试优先的 run 总是在写任何代码或测试之前先创建完整设计(架构、数据类型、边界情况、契约)。反过来,TDD 指令主动对抗这个前置设计步骤——那些 run 的设计从许多局部最小决策中涌现,很少被回头修订,倾向于落在第一个测试碰巧锁定的形状上。这也解释了 4.2 里 TDD 组测试数和实现 LOC 双低:不是精炼,是功能缺失。
5. 小步 → YAGNI。 这是一条以人为中心的收益,agent 自己做 TDD 时会丢失。理论上思考转移到了写规约的时候,但在写规约这件事上,我们没有一个类似 TDD 的机制让我们小步想透。实验里”最小实现”的指令也没能可靠阻止它们造更多东西——因为完整需求就摆在它们眼前,而我们通常不会一条一条喂过去。
6. 小步 → 快速、局部化反馈。 实验没显示 TDD 与否在调试卡壳频率上的差异。作者的一般经验是 agent 通常相当擅长搞清楚测试为什么红,即使没有小步走到那里。
7. 小步 → 信心与学习。 Kent Beck 在《Test-driven Development by Example》前言里给 TDD 的最大理由是”管理恐惧“——每个通过的测试展示进展,我们可以放松,知道进展被锁住了。而这非常明确地是关于管理一个人类的恐惧。agent 在循环内部做 TDD 时这一条不转移,因为它不能给”我”和自己一步步做时同样的控制感与信任感。这是唯一一条收益接收方是人而不是代码的——把人拿走,接收方就消失了。相关讨论见AI 生成代码泛滥,人类”理解力”成为开发新瓶颈。
七、训练数据假说与两项成本
作者和 Ivett Ördög 讨论时,对方提出了一个解释理论:
AI agent 被训练的方式是:它们看到的是完成后的函数和这些函数的描述。它们见过的真正逐步 TDD 示例在训练数据里只占极小一部分。这意味着 LLM 对代码的内部表征是从需求到代码的直接翻译,而不是如何抵达那个表征的过程。
这个假说能同时解释几件事:agent 天然倾向于想清楚整个方案再一次性写出来;TDD 提示词是”一场对抗训练数据的上坡战”;”最小实现”压不住超前实现;强化提示词能把某次 run 提到第一名但方差巨大。如果它成立,”让 agent 模仿人类过程”本身就是逆着模型能力方向使劲——约束结果比约束过程更有效。可对照开源项目Comet:强模型时代下,Agent开发从重工程化转向轻量化验证与企业 Agent 失败,不是因为模型不够大。
成本一:token 与轮次。 见第五节,倍数是方向性的,轮次翻倍是硬事实。
成本二:提示词的维护与测试。 这一项常被完全忽略,但可能才是长期成本的大头。TDD 对模型来说”不自然”,要迭代很多次提示词才能让它大部分时候遵循。作者改了提示词加强重构后,让 Opus 回看会话,Opus 确实报告了重构步骤的增加——但也列出了一些情况:agent 着手要重构,然后判断”设计已经够好了”,即使在 Opus 认为明显不够好的时候(比如所有东西都实现在一个大模块里,本可以拆成多个职责)。
这是很值得警惕的模式:你加了一条流程指令,agent 表面上执行了它,但把它降级成了空动作。指标改善,实质没有。作者另一层担心是:TDD 是一组变量很多的复杂指令,解释变异空间大,这类提示词跨模型的稳定性会比简单指令差得多——每次模型升级你都要重新验证它是否还生效。相关可见AI 编码的”双面性”:为何大模型在代码生成上表现极不稳定?。
八、结论、替代方案,与这个实验没证明什么
作者的核心判断:
我认为现在有越来越多的证据表明,对模型怎么做某件事过于具体,不是一个可持续的方法。相反,我们应该找到尽可能多的方式去监控结果并给出反馈。那种反馈应该尽可能自动化,而且我们需要仔细思考在哪里把自己插入进去,作为”什么是好的、正确的”的仲裁者。
她已经停止让 coding agent 写测试优先,直到看到 eval 或其他强论证说服她改变;转而聚焦 TDD 在 agent 循环之外的收益。注意精确性:她停掉的是第三种用法,不是 TDD 本身。
替代一:怎么拿到好的回归测试。 她仍在意扎实的回归测试——即使 agent 可能用错误方式修红灯,至少红灯给了它一个信号去复查可能被破坏的既有需求。做法是用变异测试监控和改进回归质量,而不是给一堆精心设计的 TDD 指令然后祈祷。这是”结果度量取代过程指令”的典型替换。
替代二:怎么把定期重构 build 进流程。 重构仍然至关重要,但传统 TDD 的小步骤看起来不是在 agent 循环里做它的高效方式。她列的触发器:给 agent 访问静态代码分析;定期做结构与模块化审查;建立团队仪式尽早发现漂移;盯住每次改动触及文件数的趋势;盯住每次改动消耗 token 数的趋势。
最后两条是很好的工程直觉:这两个数字上升,通常意味着模块边界正在腐化——它们是可自动采集的漂移传感器,比人工审查便宜得多。技术债的失控路径可见AI 正在消灭软件工程的「中产阶级」:编码速度越快,技术债务堆积越快与Vibe Coding 的代价:为何 AI 编码加速反而导致软件架构崩塌?;工具侧应对可参考阿里开源 AI 代码审查工具 open-code-review:定位低噪声筛查而非合并闸门。
替代三:信心从哪里来。 作者说这是最难的问题,她没有清晰答案,只提了一个好构件:Ivett Ördög 倡导的 Approved Scenarios。用她自己的话(并声明别拿这个要求 Ivett 负责):这是一种半手动测试形式,由每个应用定制的测试运行器支撑;运行器以易于思考的方式展示功能测试场景,允许她在彻底确认后在运行器里“冻结”期望(场景/fixtures),以后一旦被违反就必须再次批准。她的同事 Matteo Vaccari 分享过使用经验。
这套方法的哲学值得单独品:它把人插在“什么是正确的”这个判断点上,而不是过程的每一步里。人只在”第一次确认”和”期望被打破”两个时刻花注意力。作者的收尾判断是:无论最终是什么给了我们对软件的信心,TDD 作为我们所熟知的那个角色,会比 GenAI 之前显著更小。完整实验代码与数据在 https://github.com/birgitta410/tdd-comparisons/。
这个实验没有证明什么——引用前必须划清的边界:
- 没有证明”AI 写的测试没用”。所有 run 都带 80% 覆盖率指令,非 TDD 组照样写了最多 107 个测试。被比较的是时序与流程。
- 没有覆盖遗留代码。全部绿地。而 TDD 在人类实践中最被认为有价值的场景之一,恰恰是在没有测试网的存量代码上做改动。
- 没有覆盖大型代码库。任务是”相对小规模、纯业务逻辑”,原文自承不足以让”可测试性”浮现。
- 没有覆盖前两种用法。保留了人类检查点的模式完全没测。
- 样本量小到不能做统计推断,每格基本 n=2,作者自己反复强调并公开征集复现。
- 评委是模型。虽是盲评且刻意不给具体标准,但仍是用一个 LLM 的品味给另一个 LLM 的产出打分,系统性偏好未知。
剩下的价值是一组值得认真对待的假说,尤其”前置设计 vs 增量涌现”那条——它有机制解释、有独立佐证、也和多组数据一致。它足以让你停止把”agent 必须 TDD”当作不证自明的最佳实践,但还不足以让你反向确信”agent 绝对不该 TDD”。
九、落到自己项目上
如果你的 agent 规范里现在就写着”先写测试”,下面几步可以在不推翻任何东西的前提下拿到信息:
- 验证这条规则真的在生效。抽 5 个最近的会话记录,检查红灯是否真出现过、是否因正确原因、有没有”先写实现再补测试”。三条里有两条不达标,你已经在纯支付成本。
- 量一次成本。对比开关该规则时的会话轮次数和工具调用数——比 token 更能反映真实开销,也不受缓存口径影响。
- 换成结果侧度量。在一两个模块上引入变异测试拿到基线分数。之后无论测试怎么写出来,你都有客观数字回答”它能抓住多少回归”。
- 把前置设计显式化。既然假说指向”先做完整设计的 run 更好”,就写进规范:写任何代码之前先输出架构、数据类型、边界情况清单和契约。这条与模型默认倾向同向,阻力小、稳定性好。
- 加两个漂移传感器 + 把人插在冻结点上。采集”每次改动触及文件数”和”每次改动消耗 token 数”的趋势线,向上就是重构信号;人只在”第一次确认场景”和”冻结期望被打破”时介入,而不是每一步。
- 别忘了那两种没被测的用法。如果某个模块的正确性真的很贵(计费、结算、权限),把测试场景的所有权收回人手——你写场景,agent 写实现。
相关阅读
- AI 编程新范式:不再需要 TDD 与复杂提示词?Claude Code 引发的开发反思 — 同一议题在社区侧的另一轮讨论
- 四个工作 Agent 同题实测:好看的报告不等于可信交付 — 同样是”表面执行 vs 实质完成”的落差
- 监控OpenAI额度与Token消耗:开源工具CPA预测插件发布 — 把 token 口径落成可观测指标
- 2026年编程现状:大模型带来的是2倍而非10倍效率提升 — 对 AI 编程收益的另一份实测校准
- 探索AI编程极限:整合Claude Code高效工作流的实践与挑战 — 工作流层面的实践参考
FAQ
Q1:所以结论是”不要让 AI 写测试”吗?
不是。所有实验组都带了至少 80% 覆盖率指令,非 TDD 组反而写出了最多的测试(107 个)。被质疑的是在 agent 循环内部强制红-绿-重构这个流程,不是”要不要有测试”。作者仍然在意扎实的回归测试,只是改用变异测试去度量它。
Q2:那个 3 倍 token 会让我的账单变成 3 倍吗?
大概率不会。原文的数字用的是 getSessionStats(),把每轮的 cacheRead 也累加进去,而缓存读单价远低于新鲜输入输出。作者自己说这”很可能高估了 TDD 的真实美元成本”。但轮次翻几倍是硬事实——小任务从 10 轮到 55–68 轮,直接对应墙钟时间和上下文膨胀。
Q3:为什么 TDD 组的测试反而更少?
原文假说是:TDD 循环下 agent 一次只处理一个需求,设计从局部最小决策中涌现且很少回头修订,没被想到要写测试的行为压根没被实现。非 TDD 组先把架构、数据类型、边界情况和契约列全再动手,功能完整度更高。所以那不是”精炼”,是覆盖面缺失。
Q4:强化 TDD 提示词有用吗?
有一次有效——加了显式前置设计与重构审查后,一个 TDD 方案拿到第 1 名。但同一份提示词跑出的另一个 TDD run 排最后一名,且第 1 名花了 3,447,283 token 和 117 轮。另一个观察是:加强重构指令后 agent 确实增加了重构步骤,但也出现”着手重构、然后判定设计已够好”的空动作。
Q5:这个结论适用于遗留代码吗?
不适用。实验全部是绿地、相对小规模的纯业务逻辑任务,作者本人把这列为四条 caveat 之一。TDD 在存量代码上先写”刻画现有行为的测试”来锁住风险,这个场景一次都没被测到。
结语
这个实验最有价值的地方不是排名表,而是它示范了一种态度:面对一条被广泛接受的最佳实践,去搭一个能证伪它的装置,而不是继续引用它。
如果你今天的 agent 规范里就写着”先写失败的测试”,最低成本的下一步不是删掉它,而是去抽查五份会话记录,看看那个红灯是不是真的红过。






评论前必须登录!
立即登录 注册