name: 编写测试 description: 使用Testing Trophy模型编写关注行为的测试,使用真实依赖。适用于编写测试、选择测试类型或避免如测试模拟的反模式。
编写测试
核心原则: 使用真实依赖测试用户可观察的行为。测试应能在重构后存活。
“你的测试越像软件被使用的方式,它们给你的信心就越多。” — Kent C. Dodds
为什么这很重要: 测试存在是为了给你信心。Testing Trophy优先考虑集成测试,因为它们测试跨真实模块的真实行为——每写一个测试给出最大信心。孤立的单元测试通常只测试模拟,而不是你的实际系统。
Testing Trophy模型
| 优先级 | 类型 | 何时使用 |
|---|---|---|
| 第一 | 集成测试 | 默认 - 多个单元与真实依赖 |
| 第二 | E2E测试 | 完整的用户工作流程 |
| 第三 | 单元测试 | 仅纯函数(无依赖) |
模拟指南
默认: 不要模拟。使用真实依赖。
只模拟:
- 外部HTTP/API调用
- 时间/随机性
- 第三方服务(支付、电子邮件)
永不模拟:
- 内部模块
- 数据库查询(使用测试数据库)
- 业务逻辑
- 你自己的代码调用你自己的代码
在模拟之前,问: “这有什么副作用?我的测试需要这些吗?” 如果不确定,首先使用真实实现运行,然后只在需要的地方添加最小模拟。
测试类型决策
完整的用户工作流程? → E2E测试
纯函数(无副作用)? → 单元测试
其他所有情况 → 集成测试
断言策略
| 上下文 | 断言内容 | 避免 |
|---|---|---|
| UI | 可见文本、角色 | CSS类、内部状态 |
| API | 响应体、状态 | 内部数据库状态 |
| 库 | 返回值 | 私有方法 |
反模式
| 模式 | 修复方法 |
|---|---|
| 测试模拟调用 | 测试实际结果 |
| 生产中的仅测试方法 | 移到测试实用工具 |
sleep(500) |
使用基于条件的等待 |
| 断言内部状态 | 断言可观察输出 |
| 不完整的模拟 | 完全镜像真实API |
质量检查清单
- [ ] 覆盖快乐路径
- [ ] 处理错误条件
- [ ] 使用真实依赖(最小模拟)
- [ ] 测试能在重构后存活
- [ ] 测试名称描述行为
语言特定模式
- JavaScript/Typescript/React: 参见 references/typescript-react.md
- Python: 参见 references/python.md
- Go: 参见 references/go.md
对于有时间问题的脆弱测试,使用 Skill(ce:condition-based-waiting)。
记住: 行为优于实现。真实优于模拟。输出优于内部。