بنقرة واحدة
test-driven-development
在实现任何功能或修复 bug 时使用,在编写实现代码之前
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
在实现任何功能或修复 bug 时使用,在编写实现代码之前
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
在开始任何对话时使用——确立如何查找和使用技能,要求在任何响应(包括澄清性问题)之前调用 Skill 工具
在任何创造性工作之前必须使用此技能——创建功能、构建组件、添加功能或修改行为。在实现之前先探索用户意图、需求和设计。
中文 review 沟通参考——话术模板、分级标注(必须修复/建议修改/仅供参考)、国内团队常见反模式应对。
中文 commit 与 changelog 配置参考——Conventional Commits 中文适配、commitlint/husky/commitizen 中文模板、conventional-changelog 中文配置。仅在用户显式 /chinese-commit-conventions 时调用,不要根据上下文自动触发。
中文文档排版参考——中英文空格、全半角标点、术语保留、链接格式、中文文案排版指北约定。仅在用户显式 /chinese-documentation 时调用,不要根据上下文自动触发。
国内 Git 平台配置参考——Gitee、Coding.net、极狐 GitLab、CNB 的 SSH/HTTPS/凭据/CI 接入差异与镜像同步配置。仅在用户显式 /chinese-git-workflow 时调用,不要根据上下文自动触发。
| name | test-driven-development |
| description | 在实现任何功能或修复 bug 时使用,在编写实现代码之前 |
先写测试。看它失败。写最少的代码让它通过。
核心原则: 如果你没有看到测试失败,你就不知道它是否测试了正确的东西。
违反规则的字面意思就是违反规则的精神。
始终使用: 新功能、Bug 修复、重构、行为变更
例外(需询问你的人类伙伴): 一次性原型、生成的代码、配置文件
想着"就这一次跳过 TDD"?停下来。那是在给自己找借口。
没有失败的测试,就不写生产代码
先写了代码再写测试?删掉它。从头来过。
没有例外:
从测试出发,重新实现。句号。
流程:
run_command(command="npm test")(或 cargo test / pytest / go test),确认它因预期原因失败(功能缺失,不是拼写错误)run_command(command="npm test")(或 cargo test / pytest / go test),确认通过且其他测试未破坏测试通过了? 你在测试已有的行为。修改测试。
测试报错了? 修复错误,重新运行直到它正确地失败。
测试失败了? 修改代码,不是测试。
其他测试失败了? 立即修复。
| 特质 | 好的 | 差的 |
|---|---|---|
| 最小化 | 只测一件事。名称中有"和"?拆分它。 | test('validates email and domain') |
| 清晰 | 名称描述行为 | test('test1') |
| 展示意图 | 展示期望的 API | 掩盖了代码应该做什么 |
| 真实性 | 使用真实代码 | 测试 mock 而非真实行为 |
"我先写完再补测试来验证"
后写的测试立即通过。立即通过什么也证明不了:可能测试了错误的东西、可能测试的是实现而非行为、可能遗漏了边界情况、你从未看到它捕获 bug。
先写测试迫使你看到测试失败,证明它确实在测试某些东西。
"我已经手动测试了所有边界情况"
手动测试是临时的。没有测试记录、代码变更后无法重新运行、在压力下容易遗忘。自动化测试是系统性的,每次以相同方式运行。
"删除 X 小时的工作太浪费了"
沉没成本谬误。保留你无法信任的代码才是浪费。没有真正测试的可运行代码就是技术债。
"TDD 太教条了,务实意味着灵活变通"
TDD 就是务实的:在 commit 前发现 bug、防止回归、记录行为、支持重构。"务实的"捷径 = 在生产环境调试 = 更慢。
"后补测试也能达到相同目的——重要的是精神不是仪式"
不对。后补测试回答"这段代码做了什么?"先写测试回答"这段代码应该做什么?"后补测试受你实现的偏见影响,你验证的是你记得的边界情况,而非发现的。30 分钟的后补测试 ≠ TDD。
| 借口 | 现实 |
|---|---|
| "太简单了不用测" | 简单的代码也会出 bug。测试只需 30 秒。 |
| "我之后补测试" | 立即通过的测试什么也证明不了。 |
| "后补测试也能达到相同目的" | 后补测试 = "这做了什么?" 先写测试 = "这应该做什么?" |
| "已经手动测试过了" | 临时测试 ≠ 系统测试。无记录,无法重现。 |
| "删除 X 小时的工作太浪费" | 沉没成本谬误。保留未验证的代码就是技术债。 |
| "留作参考,然后先写测试" | 你会去改编它。那就是后补测试。删除就是删除。 |
| "需要先探索一下" | 可以。探索完了扔掉,从 TDD 开始。 |
| "测试难写 = 设计不清楚" | 听测试的。难以测试 = 难以使用。 |
| "TDD 会拖慢我" | TDD 比调试快。务实 = 先写测试。 |
| "手动测试更快" | 手动测试无法证明边界情况。每次修改你都得重新测。 |
| "现有代码没有测试" | 你在改进它。为现有代码补测试。 |
以上所有情况都意味着:删除代码。用 TDD 从头开始。
Bug: 空邮箱被接受了
红灯:
test('rejects empty email', async () => {
const result = await submitForm({ email: '' });
expect(result.error).toBe('Email required');
});
验证红灯: FAIL: expected 'Email required', got undefined
绿灯:
function submitForm(data: FormData) {
if (!data.email?.trim()) {
return { error: 'Email required' };
}
// ...
}
验证绿灯: PASS
重构: 如需,提取验证逻辑以支持多个字段。
在标记工作完成之前:
不能全部勾选?你跳过了 TDD。从头开始。
| 问题 | 解决方案 |
|---|---|
| 不知道怎么测试 | 写出你期望的 API。先写断言。问你的人类伙伴。 |
| 测试太复杂 | 设计太复杂。简化接口。 |
| 必须 mock 所有东西 | 代码耦合太紧。使用依赖注入。 |
| 测试 setup 太庞大 | 提取辅助函数。还是复杂?简化设计。 |
发现 bug?写一个重现 bug 的失败测试。按 TDD 循环走。测试既证明了修复有效,又防止了回归。绝不在没有测试的情况下修复 bug。
添加 mock 或测试工具时,避免:
生产代码 → 测试存在且先失败
否则 → 不是 TDD
没有你的人类伙伴的许可,没有例外。