测试
测试不是"写完代码后补的东西",是开发过程中的一部分。
1. 测试金字塔
txt
╱╲
╱ ╲ E2E 测试(少量)
╱────╲ - 验证完整流程
╱ ╲ - 慢、脆弱
╱────────╲ 集成测试(适量)
╱ ╲ - 验证组件协作
╱────────────╲ - 数据库、API
╱ ╲ 单元测试(大量)
╱────────────────╲ - 验证行为或规则
- 快、稳定2. 单元测试
java
@Test
void shouldCalculateDiscount() {
BigDecimal price = new BigDecimal("100");
BigDecimal discount = OrderService.calculateDiscount(price, "VIP");
assertThat(discount).isEqual(new BigDecimal("80"));
}原则
- 验证一个明确的行为或业务规则,一个行为可以跨多个协作对象
- 单元测试不依赖外部(数据库、网络)
- 协作者行为需要隔离时才用 Mock,不默认 Mock 所有依赖
- 命名清晰:
should_预期行为_when_条件
涉及 SQL、事务、序列化、框架装配、外部协议的正确性时,应交给集成测试验证真实组件协作。
3. 集成测试
集成测试验证组件协作,通常需要真实依赖(数据库、消息队列、API)。用容器化依赖(如 Testcontainers 启动真实 MySQL)减少关键依赖环境差异,测试应尽量对齐生产使用的服务版本和关键配置;涉及字符集、时区、事务隔离级别、数据库特定行为时,应显式验证相关配置与语义。
集成测试的落地代码(Testcontainers、
@SpringBootTest)见 Spring 集成测试。
4. 测试覆盖率
以下分档是经验参考,不是通用质量标准,不能据此判断核心逻辑是否已测试。
| 覆盖率 | 经验参考 | 建议 |
|---|---|---|
| < 50% | 偏低 | 可能存在测试缺口 |
| 50-70% | 一般 | 覆盖常规路径,是否足够视风险而定 |
| 70-80% | 较好 | 多数项目可参考的目标 |
| > 80% | 较高 | 核心业务建议达到 |
覆盖率衡量的是已执行的代码路径,不直接代表测试质量。行覆盖率不能说明条件分支是否充分验证,低覆盖率也不能单独证明核心逻辑缺少测试。
不要追求 100% 覆盖率:有些代码(getter/setter、配置类)不需要测试。
5. 测试最佳实践
- 先写测试再写代码(TDD)或写完代码立即补测试
- 测试应该是确定性的:避免不可控的时间、随机数和外部状态
- 测试应该快速:单元测试尽量避免不必要的 I/O 和外部依赖,集成测试耗时应与验证范围匹配
- 测试应该独立:每个测试可以单独运行
- 测试失败时信息清晰:能看出哪里出了问题