编写测试
写测试这件事,AI 是个矛盾体:它写得起飞,也写得跑偏。
起飞是因为它熟框架、会语法、能一口气写十几个 case;跑偏是因为它不知道你想测什么。你说「测一下计算器」,它能给你写一堆 expect(add(1,1)).toBe(2),把 1+1 测了八遍,但漏掉「除以零」「负数开方」「浮点精度」这些真正会出问题的边界。
让 Claude 写出有用测试的关键,是给它验证标准和点名边界。
第一招:给验证标准——example test cases
Section titled “第一招:给验证标准——example test cases”官方 best-practices 强调的一个原则:Provide verification criteria。不要让 Claude 猜你想要什么,把标准写出来。
最直接的方式是给几个示例 case:
write unit tests for the calculator functions. cover at least these cases:- add(2, 3) === 5- add(-1, 1) === 0- divide(10, 0) should throw or return Infinity, depending on current behavior- divide(10, 3) should handle floating point correctlyadd more edge cases you think matter, but don't skip these这份 prompt 给了 Claude 必须命中的目标——四个具体 case,每个都对应一种风险(负数、异常、精度)。它不能跑题。
「add more edge cases you think matter」这一句也很妙——它告诉 Claude「你自由发挥,但不要少给」。AI 在有「必须命中」锚点的情况下,反而更能补出有价值的额外 case。
第二招:点名边界用例
Section titled “第二招:点名边界用例”笼统的「写测试」会让 Claude 写出泛泛而谈的 happy path。要让它写出有用的测试,直接点名你担心的边界:
write a test for src/auth/permissions.py covering the edge case where the user is logged out. verify that:- the function returns PermissionDenied, not None- the error message contains the user id- no side effects (no db writes, no logging)avoid mocks — use real fakes or in-memory fixtures注意最后一句 avoid mocks——这是一个很值钱的指令。Claude 默认会大量用 mock,因为它「安全」,但 mock 太多会让测试变成「测 mock 而不是测代码」。明确禁掉 mock,逼它去搭真实的 in-memory fixture,测试质量会高一截。
第三招:让 Claude 跑测试,看结果,迭代
Section titled “第三招:让 Claude 跑测试,看结果,迭代”写完测试不算完——让它跑:
run the tests. paste the failures. then iterate: fix the test or fix the code, but tell me which one you're fixing and why为什么这一步重要?因为 Claude 写的测试经常自己就跑不通——可能是 import 路径错、fixture 没建对、异步处理漏了 await。让它跑一遍,看到红,自己修,再跑——这比它闷头写完一份「看起来对但跑不起来」的测试强十倍。
「tell me which one you’re fixing」这一句也很有用——它逼 Claude 把判断讲出来:是测试错了(改测试)还是代码错了(改代码)。这个区分本身就是测试的价值。
TDD 模式:先写失败测试
Section titled “TDD 模式:先写失败测试”Test-Driven Development 在 AI 时代反而更香了——因为写测试这个最枯燥的部分,可以让 Claude 代劳。
I want to add a feature: rate limiter that allows 100 requests per minute per user, returning 429 when exceeded.
step 1: write failing tests that specify the behavior. don't implement yet.step 2: show me the failing test output.step 3: implement the minimum to make tests pass.step 4: refactor for clarity, keep tests green.这个 prompt 把 TDD 的红-绿-重构三步直接交给 Claude 跑。Step 1 它写测试(红),Step 2 它跑给你看(验证红),Step 3 它写实现(变绿),Step 4 它重构(保持绿)。
每一步你都审计——Step 1 看测试是否覆盖了你想要的行为,Step 2 确认测试真的失败了(不是假红),Step 3 看实现是否最小化,Step 4 看重构有没有偷换概念。
测试 + Hooks:PostToolUse 自动跑
Section titled “测试 + Hooks:PostToolUse 自动跑”如果你写测试写得频繁,可以挂个 Hook 让 Claude 每次改完代码自动跑测试——不用你提醒。
在 .claude/settings.json 里:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "npm test -- --silent 2>&1 | tail -20" } ] } ] }}每次 Claude 用 Edit 或 Write 改文件,PostToolUse Hook 自动跑一遍测试,结果塞回它的上下文。这意味着 Claude 在改代码的同时能立即看到测试是否还绿——出问题当场修,而不是等你回头发现。
把 npm test 换成你的测试命令(pytest、go test、cargo test)即可。-- --silent 和 tail -20 是为了避免输出太长撑爆上下文,只把摘要塞回去。
更精细的版本——只跑受影响的测试:
{ "type": "command", "command": "pytest $CLAUDE_FILE_PATHS -x --tb=short 2>&1 | tail -30"}$CLAUDE_FILE_PATHS 是 Hook 注入的环境变量,包含刚才被改的文件——pytest 能据此跑相关测试,更快更省。
一份可复制的「写测试」模板
Section titled “一份可复制的「写测试」模板”Target: [要测的文件/函数]Framework: [Jest/pytest/go test/...]Must-cover cases:- [case 1: 正常路径]- [case 2: 边界值]- [case 3: 异常/错误路径]- [case 4: 并发或性能相关,如适用]
Constraints:- avoid mocks where possible; use real fakes- test behavior, not implementation (don't assert private method calls)- each test must be independent — no shared mutable state
After writing:- run the test suite- paste failures- iterate until green, telling me whether you're fixing test or code填空,丢给 Claude。剩下的事,它会做得比你想象的好。
- 想让 Claude 自动跑测试——回顾 Hooks 深入与实战。
- 测试写好了,准备发 PR——看 创建 Pull Request。
- 想用 TDD 思路修 Bug——读 高效修 Bug。