Codex 测试驱动开发:让 AI 先写测试,再修到全绿

"OpenAI Codex best practices 建议在任务中明确 Goal、Context、Constraints 和 Done when,并把测试、检查、review 作为完成标准。"
你在终端里看到 Codex 输出”所有测试已通过”,但仔细一看,它只贴了结论,没贴命令,也没说跑了哪些测试。打开 diff,发现测试文件也被改了——断言从 toEqual(42) 变成了 toBeTruthy()。不是不信 Codex,是不信这种没有证据的”全绿”。这篇文章提供一套可复制的操作模板、证据验收清单和防假绿护栏,把”信任 AI”变成”看可复现证据”。
为什么测试先行对 Codex 更重要
测试先行不只是”先写测试再写代码”。在 Codex 时代,测试是机器可执行的验收标准——Codex 能跑命令、看输出、改文件,但它判断”完成”的标准需要你事先写清楚。
根据 OpenAI Codex 官方文档,Codex 在能验证工作的情况下输出质量更高。这意味着:如果你能告诉 Codex 怎么验证、用什么命令、期望什么结果,它更有可能做出正确改动。模糊的任务容易被泛泛处理,小任务更容易验证和审查。
red-green-refactor 三阶段循环:
| 阶段 | Codex 做什么 | 你看什么证据 |
|---|---|---|
| Red | 只写测试,不写实现 | 失败测试名、失败断言 |
| Green | 最小实现,不改测试 | 通过测试、修改文件列表 |
| Refactor | 清理结构,重跑测试 | 仍然全绿、diff 不含测试文件 |
这三步不可省略。跳过红灯,就不知道测试是否真的在验证新行为;跳过 refactor,就容易堆出拼凑代码。更多 Codex 入门内容见 Codex 完全入门指南。
Red Phase:让 Codex 只写可失败的测试
Red phase 的核心是约束:只修改测试文件,不写实现代码。让 Codex 先列出测试清单,再逐个生成,最后运行测试确认红灯。
Prompt 模板
只修改测试文件,不要修改实现代码。
为 [功能名] 写以下测试场景:
1. [最小行为]
2. [边界条件]
3. [错误路径]
完成后运行 `npm test`,贴出失败测试名和断言。
这个 prompt 必须包含”不要写实现”。没有这句话,Codex 可能在写测试的同时顺手写实现,破坏红灯验证。
确认红灯
Codex 完成后,要求它贴出完整的测试输出。红灯必须失败在预期断言上,而不是编译错误或导入失败。如果你看到:
FAIL src/utils/calculator.test.ts > add > should handle negative numbers
AssertionError: expected -1 to be 42
说明测试在验证负数输入的行为,失败在预期位置。如果只看到 TypeError: Cannot find module 'calculator',那红灯是编译错误,不是测试失败。
测试清单排序
不要让 Codex 一次生成几十个测试。从最小行为、边界条件、回归 bug、错误路径开始,逐个推进。测试清单可以写在 AGENTS.md 或单独文档里,让 Codex 按清单逐个完成。
单元测试基础见 Vitest 单元测试与 TDD 和 Vitest 实战指南。
Green Phase:最小实现修到全绿
Green phase 的硬护栏:测试文件禁止修改。如果测试失败,Codex 只能改实现,不能改测试迁就实现。
Prompt 模板
只修改实现文件,不要修改测试文件。
做最小改动让测试通过。
完成后运行 `npm test`,贴出通过摘要。
这个 prompt 必须包含”不要修改测试文件”。没有这句话,Codex 可能会修改断言、删除测试、跳过用例来让测试变绿。
检查通过摘要和 diff
Codex 完成后,要求贴出测试数量、通过数、耗时:
PASS src/utils/calculator.test.ts (1.2s)
add
✓ should add two numbers (5ms)
✓ should handle negative numbers (3ms)
2 tests passed
然后检查 diff。如果测试文件出现在变更列表里,直接拒绝这个 green phase。
防假绿护栏
假绿是 TDD 的最大风险。以下 6 个信号必须警惕:
| 假绿信号 | 怎么拦住 |
|---|---|
| 测试文件被修改 | 检查 diff,拒绝包含测试文件的 green phase |
断言从 toEqual(42) 变成 toBeTruthy() | 要求 Codex 贴出完整断言,人工对比 |
新增 test.skip() / test.only() | grep 测试文件,禁止新增 skip/only |
matcher 放宽(toBe → toBeTruthy) | 对比测试 diff,禁止放宽 matcher |
| fixture 被改成”正确答案” | 检查 fixture diff,禁止修改输入数据 |
| 只跑单元测试,不跑集成测试 | Done when 必须包含所有相关测试命令 |
这些护栏不是 Codex 自动执行的,而是你审查时必须检查的点。自动化程度高的团队可以把部分检查写进 CI 或 pre-commit hook。
Refactor Phase:全绿后再清理
Refactor phase 只能在绿灯后进行。没有通过测试,不要重构。重构后必须重新跑测试,不能只看 diff。
Prompt 模板
所有测试已通过。现在只做重构:
- 重命名变量让意图更清晰
- 去重复代码
- 抽取函数
不要修改测试文件。完成后重新运行 `npm test`。
这个阶段 Codex 只改结构,不改行为。如果重构引入新逻辑,那就不是 refactor,而是新功能的 green phase。
重跑测试验证
重构完成后,Codex 必须运行同一组测试。如果测试全绿,说明重构没有破坏现有行为。如果测试失败,说明重构改变了行为,需要回退或修复。
检查 diff:测试文件不应出现在变更列表中。如果测试文件被改,说明 refactor 越界了。
重构案例见 AI 重构与测试安全网。
证据包:让 Codex 交出可审查的证据
每个阶段结束前,Codex 必须交出以下证据:
完成前验收清单
- 测试命令和 exit code
- 失败/通过摘要
- 修改文件列表
- 测试文件是否被修改
- CI status checks(如有)
完成回复模板
让 Codex 按以下格式回复:
### 测试结果
- 命令:`npm test`
- Exit code:0
- 通过:42 个测试
- 失败:0
- 耗时:1.2s
### 变更文件
- src/utils/calculator.ts
- (测试文件未修改)
### 剩余风险
- 未覆盖边界条件:负数输入
这个模板让证据可读、可对比、可存档。如果 Codex 只回复一句”测试通过”,你无法判断它是否真的跑了测试、是否改了测试文件、是否遗漏边界条件。
测试层选择与命令示例
不同测试层适合不同验证场景。不要一上来就写全量 E2E,也不要只写快照测试。
测试层决策表
| 测试层 | 什么时候用 | 命令示例 | 交给 Codex 的证据 |
|---|---|---|---|
| 单元测试 | 快速验证单个函数 | npm run test:unit 或 vitest run 或 pytest | 失败测试名、断言 |
| 集成测试 | 验证模块交互 | npm run test:integration | 失败模块、接口 |
| E2E 测试 | 验证用户流程 | npx playwright test | 失败场景、截图 |
| 类型检查 | 编译期错误 | npm run typecheck 或 tsc --noEmit | 错误文件、行号 |
| Lint | 代码规范 | npm run lint 或 eslint | 错误文件、规则名 |
| CI | 团队门禁 | GitHub Actions | Status checks 页面 |
命令示例按”替换成你的项目命令”原则使用。不同项目测试框架不同:Jest、Vitest、Pytest、Playwright、GitHub Actions。更多测试框架内容见 Next.js Jest 测试指南。
单元测试适合作为 Codex 的首选验证层。它跑得快、失败信息明确、容易在 AGENTS.md 里写清楚测试命令。集成测试和 E2E 测试适合验证多模块交互和用户流程,但失败原因更难定位。类型检查和 Lint 可以作为补充验证,捕获编译错误和代码规范问题。CI 是团队最后的门禁,所有本地测试全绿后,必须等 CI status checks 通过才能合并。
AGENTS.md 与 prompt 固化
把 TDD 规则写进 AGENTS.md,让 Codex 每次工作前都读取。避免每次都重复写 prompt。
AGENTS.md 小样例
在项目根目录或局部目录放以下内容:
## Test commands
- Run tests: `npm test`
- Run unit tests: `npm run test:unit`
- Run typecheck: `npm run typecheck`
## TDD rules
- Red phase: only modify test files
- Green phase: only modify implementation files
- Refactor phase: must re-run tests after cleanup
## Done when
- All tests pass
- Test files are not modified in green/refactor phase
- Diff contains only expected changes
这个文件让 Codex 知道项目有哪些测试命令、每个阶段允许做什么、完成的标准是什么。更多 AGENTS.md 写法见 Codex 项目规则(同系列文章)。
局部目录可以写更具体的规则。例如 src/utils/AGENTS.md 可以列出 src/utils/ 目录的测试场景、边界条件和已知 bug。
不要在 AGENTS.md 里写密钥、token 或敏感配置。Codex 会读取这个文件,但不会自动过滤敏感信息。
从本地到团队:CI 门禁
本地测试全绿不等于可合并。团队有 CI 门禁:required status checks 必须通过,PR review 必须完成。
流程清单
- 本地测试全绿:Codex 完成三阶段,贴出证据包
- review pane diff 检查:查看测试文件是否被修改
- 创建 PR:推送到 feature branch
- required status checks 必须通过:CI 跑完整测试、typecheck、lint
- 人工 review:审查 diff、证据包、剩余风险
测试全绿不等于自动合并
GitHub Docs 说明:required status checks 必须通过才能 merge 到 protected branch。但有一个风险:skipped job 会报告 success,不会阻止 PR merge,即使它是 required check。这意味着如果 workflow 被跳过,PR 可能被合并,即使某些检查没有真的跑。
防止 workflow 被跳过造成假绿:检查 GitHub Checks 页面,确认所有 required checks 都真的跑过,而不是被 skip。
review pane 使用
Codex app 的 review pane 可以查看 diff 是否包含测试文件修改。按 file 或 hunk 粒度 stage/unstage/revert。如果测试文件被改,直接 revert 测试文件变更,只保留实现文件变更。
更多 CI 内容见 GitHub Actions CI 和 GitHub Actions Workflow 基础。PR review 流程见 Codex AI 代码审查(同系列文章)。
CI 失败自动修复边界
codex exec 和 Codex GitHub Action 可以处理 CI 失败测试,但有安全边界。
失败测试自动修复流程
根据 Codex non-interactive 文档,CI 失败自动修复的流程是:
- 先运行测试复现失败
- 让 Codex 做最小修复
- 生成 patch artifact
- 开 PR 分离修复代码
使用 npm test 2>&1 | codex exec "总结失败原因并建议最小修复" 可以把测试输出管给 Codex,让它总结失败和建议修复。
安全原则
不要让 Codex 同时拥有写仓库和访问密钥的权限。使用最小权限 sandbox:read-only 默认,workspace-write 仅限工作目录,danger-full-access 只适合受控环境。
生成 patch artifact 与开 PR 分离,避免把 API key 暴露给不可信代码。
不展开完整 GitHub Action YAML,只给原则:最小权限、patch 分离、人工合并。更多自动化内容见 codex exec 自动化(同系列文章)。
总结
Codex 测试驱动开发的核心是三阶段操作模板:Red 只写测试,Green 只写实现,Refactor 清理后重跑测试。每个阶段都必须让 Codex 交出可审查的证据:命令、失败/通过摘要、修改文件列表。
防假绿护栏是本文的核心差异化:检查测试文件是否被修改、断言是否被放宽、测试是否被 skip、fixture 是否被改动、是否只跑单元测试不跑集成测试、CI workflow 是否被 skip。
团队落地时,本地测试全绿不等于可合并。必须等 CI status checks 通过、PR review 完成、protected branch 允许 merge。
下次让 Codex 改代码时,先让它写测试、确认红灯、再看证据。不要只看”测试通过”四个字。
用 Codex 做一轮 TDD
把需求拆成 red、green、refactor 三轮,让 Codex 先写失败测试,再做最小实现,最后用测试输出、diff 和 CI 验收。
- 1
步骤 1: 列测试清单
让 Codex 根据需求列出最小行为、边界条件和回归场景,不写实现。 - 2
步骤 2: 写失败测试
让 Codex 只改测试文件,并运行相关测试确认红灯。 - 3
步骤 3: 做最小实现
让 Codex 不改测试断言,只修改实现代码并运行同一组测试。 - 4
步骤 4: 全绿后重构
在测试通过后清理结构,再重新运行测试。 - 5
步骤 5: 检查证据和 diff
查看命令输出、测试文件变更、review pane 或 PR diff,以及 CI status checks。
常见问题
Codex 能写单元测试吗?
怎么让 Codex 真跑测试?
测试失败时 Codex 能改测试吗?
覆盖率数字能当质量标准吗?
前端页面怎么验证?
什么时候不适合用 TDD 驱动 Codex?
11 分钟阅读 · 发布于: 2026年7月30日 · 修改于: 2026年7月30日
Codex 实战专题:CLI、桌面 App、Cloud 与团队工作流
如果你是从搜索进入这篇文章,建议顺手补上上一篇或继续下一篇,这样更容易把同一主题读完整。



评论
使用 GitHub 账号登录后即可评论