用 AI 写代码时,最容易出现的体验是:前期很快,后期很乱。功能刚开始能迅速搭起来,但项目一大、修改次数一多,就会出现一个 bug 改完又冒出三个 bug 的情况。
这不完全是 AI 的问题。很多人写代码也会这样,只是 AI 写得更快,问题暴露得也更快。要减少这种失控,关键不是让 AI “更努力”,而是给它更清晰的边界:先说明什么结果算对,再让它写实现。
TDD 和 BDD 就适合放到 AI 编程流程里。TDD 负责把“对不对”变成自动测试,BDD 负责把“是不是我要的功能”变成人能看懂的行为描述。两者结合,可以让 AI 少猜、少自由发挥,也更容易被检查。
TDD 解决什么问题
TDD 是 Test Driven Development,也就是测试驱动开发。它的基本顺序是:
- 先写测试。
- 运行测试,确认它现在失败。
- 再写功能代码。
- 持续修改实现,直到测试通过。
这和很多人习惯的做法相反。平时写一个排序函数,直觉上会先写函数,再随便输入几个数字看看结果对不对。TDD 则要求先把预期写成测试,例如输入 [3, 1, 2] 时应该得到 [1, 2, 3],输入空数组时应该返回空数组,输入包含重复数字时结果也应该正确。
这样做的意义是:开发开始前,正确结果已经被定义清楚了。后面无论谁改代码,只要重新跑测试,就能知道有没有破坏之前约定好的行为。
为什么 TDD 以前不容易坚持
TDD 听起来很美,但在真实项目里并不容易长期执行。
一是它反直觉。面对一个空文件时,很多人更想先把功能写出来,而不是先写测试。尤其需求还不清楚时,测试用例也很难落笔。
二是需求变化快。今天认真写下的十几个测试,明天需求一改,可能就要大面积重写。短期看,它会让开发节奏变慢。
三是测试本身也需要成本。测试代码不是凭空出现的,过去它需要程序员自己写、自己维护、自己解释价值。对只看短期交付速度的团队来说,这件事很容易被压掉。
但 AI 改变了这个成本结构。把需求转成测试代码,恰好是 AI 很擅长的工作。让 AI 根据测试去补实现,也比让它对着一段模糊描述自由发挥可靠得多。
AI 写代码时怎么用 TDD
使用 AI 写功能时,可以把提示方式从“帮我实现这个功能”改成下面这个顺序:
- 让 AI 先根据需求列出测试用例。
- 要求每个测试用例都有中文说明。
- 先 review 测试用例是否符合真实需求。
- 确认测试后,再让 AI 写功能实现。
- 要求 AI 运行测试,并根据失败结果继续修正。
这时,人主要 review 的不是一大段实现代码,而是测试是否说清楚了需求。测试用例通常更接近“输入是什么、输出应该是什么、边界情况怎么处理”,比直接读实现逻辑轻松很多。
例如可以这样要求 AI:
|
|
这个流程能减少两类常见问题:一类是 AI 写着写着偏题,另一类是后续修改时把旧功能改坏。
TDD 还不够
只有 TDD 仍然有两个缺口。
第一个缺口是:测试都通过,不等于产品真的符合预期。测试只能证明代码满足了测试里写下的规则。如果测试本身没有表达清楚用户需求,代码仍然可能“正确地做错事”。
第二个缺口是:测试代码对非技术用户仍然不友好。哪怕有中文注释,很多人还是不愿意阅读一堆单元测试。需求越偏产品体验,越难直接从测试代码里确认“这是不是我要的东西”。
这时就需要 BDD。
BDD 解决什么问题
BDD 是 Behavior Driven Development,也就是行为驱动开发。它关注的不是代码内部怎么写,而是系统在某个场景下应该表现出什么行为。
BDD 常用的描述方式是 Given / When / Then:
Given:给定某个前置状态。When:当用户或系统执行某个动作。Then:应该得到某个结果。
例如一个带吸血效果的游戏角色,可以这样描述:
|
|
这段话不是代码,但它比“攻击敌人时恢复生命”精确得多。它说明了初始状态、动作和结果,也暴露出后续需要补充的问题:如果敌人只剩 1 点血,吸血鬼按造成伤害恢复,还是按攻击力恢复?如果吸血鬼已经满血,溢出的治疗怎么处理?
这些问题越早被问出来,AI 后面越不容易乱猜。
为什么 BDD 很适合 AI
BDD 过去推行成本也不低。它要求产品、开发、测试用同一套行为描述沟通,而现实里很多团队并没有这种协作习惯。
但 AI 时代,BDD 的成本下降了。你只需要先写一句粗略需求,例如:
|
|
然后让 AI 生成 Given / When / Then 场景。做得好的 AI 会主动补充边界情况,并追问不明确的规则。你需要做的是确认这些行为描述,而不是直接读实现代码。
一旦行为描述确认清楚,再让 AI 把它转换成测试代码,最后根据测试实现功能,路径就顺了很多。
一套更稳的 AI 编程流程
实际使用时,可以把 BDD 和 TDD 串起来:
- 先用自然语言写需求。
- 让 AI 转成 BDD 行为场景。
- 人确认 Given / When / Then 是否符合预期。
- 让 AI 把行为场景转换成自动测试。
- 人快速 review 测试覆盖范围。
- 让 AI 实现功能。
- 运行测试,失败就让 AI 根据错误继续修正。
- 最后再做一次人工验收和代码 review。
这里的关键是顺序。不要一开始就让 AI 写完整实现,而是先让它把需求变成可确认的行为,再变成可执行的测试。这样 AI 的自由发挥空间会小很多。
可以直接使用类似这样的提示词:
|
|
这类提示词不复杂,但能明显改变 AI 的工作方式。它会先收敛需求,再进入实现,而不是一上来就写一堆看似完整、实际难以验证的代码。
适合优先使用的场景
BDD + TDD 不一定适合所有任务。对于一次性脚本、临时数据处理、小范围样式调整,完整流程可能太重。
它更适合这些场景:
- 业务规则多,容易理解错。
- 边界条件多,后续还会持续修改。
- 游戏、计费、权限、状态机、表单校验等逻辑密集功能。
- 需要多人协作确认需求。
- 代码将长期维护,不只是一次性生成。
- 已经出现“AI 越改越乱”的项目。
如果只是让 AI 改一个按钮文案,不必上完整流程。但如果要做一套角色技能系统、订单状态流转、权限判断、积分规则,先写行为场景和测试会更划算。
使用时注意什么
第一,测试不是越多越好。测试应该覆盖关键规则和高风险边界,而不是把实现细节全部锁死。否则需求稍微变化,测试就会变成维护负担。
第二,BDD 场景要写具体。不要写“系统应该正常工作”“体验应该流畅”这类无法验证的描述。要写清楚给定什么状态、发生什么动作、结果应该是什么。
第三,人仍然要 review。AI 可以生成测试和行为场景,但它不知道你真正想要的产品取舍。尤其是边界规则,必须由人确认。
第四,测试通过后还要实际运行功能。自动测试能兜住逻辑问题,但界面体验、性能、交互细节、用户感受仍然需要人工验收。
小结
AI 写代码快,但快不等于稳。越是复杂需求,越不能只靠一句“帮我实现”。更好的方式是先把需求拆成可确认的行为,再把行为变成可运行的测试,最后让 AI 按测试实现代码。
TDD 让 AI 知道什么结果算对,BDD 让人更容易确认这是不是自己想要的功能。两者合起来,不是为了增加仪式感,而是为了减少 AI 的猜测空间,把“写得快”变成“改得稳”。