测试模式
构建可靠测试体系的原则。
1. 测试金字塔
/\ E2E(端到端,少量)
/ \ 关键流程
/----\
/ \ Integration(集成测试,中量)
/--------\ API、数据库查询
/ \
/------------\ Unit(单元测试,大量)
函数、类等基础逻辑
2. AAA 模式
| 步骤 | 目的 |
|---|---|
| Arrange(准备) | 准备测试数据与上下文 |
| Act(执行) | 执行被测代码 |
| Assert(断言) | 断言结果是否符合预期 |
3. 测试类型选择
各类型使用时机
| 类型 | 适用场景 | 速度 |
|---|---|---|
| Unit(单元测试) | 纯函数、核心逻辑 | 快(<50ms) |
| Integration(集成测试) | API、数据库、服务协作 | 中 |
| E2E(端到端测试) | 关键用户流程 | 慢 |
4. 单元测试原则
优秀单元测试特征
| 原则 | 含义 |
|---|---|
| Fast(快速) | 单个用例 < 100ms |
| Isolated(隔离) | 不依赖外部系统 |
| Repeatable(可重复) | 每次结果一致 |
| Self-checking(自校验) | 无需手工验证 |
| Timely(及时) | 与代码同步编写 |
单元测试该测什么
| 应该测试 | 不应测试 |
|---|---|
| 业务逻辑 | 框架内部实现 |
| 边界条件 | 第三方库本身 |
| 错误处理 | 过于简单的 getter(取值器) |
5. 集成测试原则
重点覆盖
| 领域 | 关注点 |
|---|---|
| API 端点 | 请求/响应链路 |
| 数据库 | 查询与事务行为 |
| 外部服务 | 契约一致性 |
Setup/Teardown(准备/清理)约定
| 阶段 | 动作 |
|---|---|
| Before All(全局前置) | 建立资源连接 |
| Before Each(用例前置) | 重置状态 |
| After Each(用例清理) | 执行清理 |
| After All(全局清理) | 释放连接 |
6. Mock(模拟)原则
何时需要 Mock
| 应该 Mock | 不应 Mock |
|---|---|
| 外部 API | 被测代码本身 |
| 数据库(单元测试) | 简单依赖对象 |
| 时间/随机数 | 纯函数 |
| 网络请求 | 内存型替代实现 |
Mock 类型
| 类型 | 用途 |
|---|---|
| Stub(桩) | 返回固定值 |
| Spy(监视) | 跟踪调用行为 |
| Mock(模拟) | 预设期望并校验 |
| Fake(伪实现) | 提供简化实现 |
7. 测试组织方式
命名规范
| 模式 | 示例 |
|---|---|
| Should(行为式) | "should return error when..." |
| When(条件式) | "when user not found..." |
| Given-When-Then(前提-条件-结果) | "given X, when Y, then Z" |
分组方式
| 层级 | 用途 |
|---|---|
| describe(分组) | 归类相关测试 |
| it/test(用例) | 单个测试用例 |
| beforeEach(前置) | 共享初始化逻辑 |
8. 测试数据策略
常见策略
| 方法 | 用途 |
|---|---|
| Factories(工厂) | 动态生成测试数据 |
| Fixtures(夹具) | 预定义数据集 |
| Builders(构建器) | 链式构建对象 |
基本原则
- 使用贴近真实的数据
- 非关键字段可随机化(faker 数据生成库)
- 共享公共 fixtures(预置数据)
- 保持最小必要数据集
9. 最佳实践
| 实践 | 目的 |
|---|---|
| 单测关注单一断言目标 | 失败原因更清晰 |
| 用例相互独立 | 避免顺序依赖 |
| 保持测试快速 | 能高频执行 |
| 命名具描述性 | 测试即文档 |
| 严格清理状态 | 避免副作用污染 |
10. 反模式
| [FAIL] 禁止(Don't) | [OK] 推荐(Do) |
|---|---|
| 测实现细节 | 测可观察行为 |
| 重复测试代码 | 使用 factories(工厂)复用 |
| 测试前置过于复杂 | 简化或拆分场景 |
| 忽略 flaky(不稳定)测试 | 修复根因 |
| 不做清理 | 重置状态 |
牢记: 测试本身就是文档。如果别人无法通过测试理解代码行为,就应该重写测试。