为 AI Agent 实现测试驱动开发 (TDD)

AI agent 经常会生成模糊、过度复杂或同义反复的测试,因为它们是在通常缺乏质量的人类编写示例上进行训练的。为了克服这一点,开发者可以为 agent 提供特定的“技能”——基于永恒软件工程原则的结构化指导——以强制执行理性的测试驱动开发 (TDD) 流程。

Specify-Encode-Fulfill (SEF) 循环

有效 AI TDD 工作流的核心是 Specify-Encode-Fulfill (SEF) 循环,它作为传统 red-green-refactor 循环的高层替代方案。这一过程确保了 AI 在尝试编写代码之前理解需求。

  1. Specify: 为功能或修复定义清晰的规范。
  2. Encode: 将这些规范转化为自动化的、可执行的测试。
  3. Fulfill: 编写满足规范所需的最小量代码。

将 Canon TDD 应用于 AI Agent

集成 Kent Beck 的 Canon TDD 可以为 agent 提供战术指导,以避免“投机性编码”——即编写比实际需要更多的代码,这会带来引入未经测试逻辑的风险。

其操作流程遵循以下步骤:

  • List Specifications: 在当前会话范围内创建一个全面的规范列表。
  • Encode Tests: 将列表中的每个项目转换为自动化测试。
  • Incremental Implementation: 仅进行足够的代码更改,以使当前的测试失败消失。
  • Isolated Refactoring: 仅在提交行为变更后进行重构;绝不要将行为变更与重构混合在一起。
  • Iteration: 重复该过程,直到规范列表为空。

多 Agent 评审与设计验证

为了减少偏差并提高代码质量,建议采用多 agent 架构。为不同角色使用独立的 agent 可以防止主 agent 忽视自身的错误。

测试设计评审

专门的 Test Design Review agent 会分析测试是否存在违反设计原则的情况,特别是检查测试是否关注“手段”(如何实现)而非“结果”(结果是什么)。

软件设计评审

通用的软件设计原则,例如准确命名(“实事求是地命名”),通过 Software Design Review 技能来强制执行。这确保了 TDD 流程不仅能产生通过的测试,还能产生可维护的代码。

“清理厨房”启发式方法

在 agent 指令中加入直观的比喻可以产生出意想不到的效果。例如,指示 agent 如果一个测试难以编写,它可能需要“在做饭前清理厨房”(重构现有代码以使新功能更容易实现),这会鼓励 agent 停下来并建议必要的准备性重构。

社区观点与反论点

虽然 SEF 循环提供了一条通往质量的结构化路径,但开发者社区在 LLM 时代 TDD 的效用上存在分歧。

支持在 AI 工作流中使用 TDD 的论点

某些开发者认为,测试是让 AI 保持在护栏内的最关键杠杆。一位用户指出,生成独立的 agent 进行评审可以显著提高代码质量并减少 bug,并认为额外的 token 成本低于后期修复 bug 的成本:

"生成独立的 agent 来评审原始 agent 的实现,会导致代码质量非常明显地提高,并且 bug 减少。"

反对在 AI 工作流中使用 TDD 的论点

批评者认为,由于 token 成本以及 AI 倾向于“幻觉”测试或仅仅是更新测试以匹配有 bug 的代码(而不是修复代码本身),在 agentic 开发中应用 TDD 是低效的。

  • Token Overhead: 一些用户声称 TDD 会“使 token 成本激增”,并且与“瀑布式”方法相比,开发速度会慢得像爬行一样。
  • Fragility: 有人担心 AI 可能会在测试失败时直接修正测试,从而有效地将规范更改为匹配实现,而不是修复代码。
  • Redundancy: 一些人认为现代 LLM 可以编写出很大程度上没有 bug 的专家级代码,使得 TDD 的开销销开销变得多余。

验证策略

为了确保测试不仅仅是表面化的,有人建议进行一次验证环节,即故意向代码中注入 bug,以验证测试是否真的会失败,从而确认测试具备检测回归的问题的能力。

Sources