单元测试

单元测试既证明代码局部正确,也控制变化带来的系统性风险

单元测试的第一性原理

软件系统的三个不变事实

  1. **变化不可避免**:需求变化、人员流动、环境演进是常态
  2. **人必然会犯错**:复杂系统中不存在零缺陷工程
  3. **复杂度只增不减**:系统一旦上线,复杂度随时间单调上升

单元测试的独特价值

不可替代性矩阵

能力单元测试集成测试E2E测试
快速反馈(分钟级)
精确定位失败
成本稳定可预测
约束架构设计
为重构提供信心

不可替代的根本原因

1. 代码级细粒度

单元测试验证的是最小行为单元的正确性。只有在代码级别,才能精确控制每一个执行路径、验证每一次副作用变更、隔离任意依赖项。

2. 确定性来源

单元测试的确定性来自受控的内部状态,而非外部环境的真实协作。当外部系统被替身后,测试才能做到任意时间可重复、任意环境一致、任意顺序执行。

3. 与代码共生演进

单元测试随代码同步创建、随代码同步重构、随代码同步删除。

与其他测试层的协同

┌─────────────────────────────────────────────────────┐│                     E2E 测试                         ││         验证完整业务链路与用户旅程                   │├─────────────────────────────────────────────────────┤│                     集成测试                         ││         验证组件边界与协作协议                      │├─────────────────────────────────────────────────────┤│                     单元测试                         ││         验证最小单元行为与设计契约            ▲     │└─────────────────────────────────────────────────────┘                              只有单元测试能到达的深度

单元测试不替代其他测试,其他测试也替代不了单元测试。

单元测试的核心原则体系

AIR 原则(工程稳定性)

FIRST 原则(反馈效率)

原则不是规范,而是工程决策的约束条件。真正的工程智慧在于:在约束内找到最适合当前场景的方案,而非机械套用原则。

单元测试的边界与粒度

什么是”单元”

单元并非语法层面的方法或类,而是:

一个职责闭合、行为可预测、依赖可替换的最小行为单元

粒度选择原则

单元测试的复杂性来源

  1. **输入复杂性**:一切影响执行路径的因素
  2. **输出复杂性**:所有被修改的状态与副作用
  3. **依赖复杂性**:外部系统、时间、随机性

应对复杂性的唯一方式是:

控制变量,而不是增加断言。

测试代码的工程规范

测试即文档

assertUserExists("cxk");

好的测试 API 是业务语言的直接表达。

断言策略

命名原则

可测性:架构质量的外显指标

不可测的根因

可测性改造策略

重构不是为了测试,测试是为了暴露重构需求。

覆盖率的工程语境

覆盖率的本质

覆盖率是风险可见性指标,而非质量指标。

决策导向的覆盖策略

场景推荐覆盖
核心业务分支 / 条件
工具代码行覆盖
遗留系统新增路径

测试数据构造策略

测试数据的构造方式决定了测试的可控性与覆盖广度

构造模式适用场景核心特征
精确构造核心路径验证已知输入、确定输出
边界构造异常路径覆盖极值、null、空场景
随机构造鲁棒性验证大量迭代、边界穿透
替身构造依赖隔离内存替身、虚假实现

策略原则

测试策略的层级分布

不同抽象层级的代码,其测试策略应由其职责边界决定:

边界层(数据访问、基础设施)

业务层(服务、领域逻辑)

纯函数层(工具类、算法)

组织与文化视角

单测失败的真实原因

单元测试的真正价值

单元测试是对"代码会按预期运行"这一承诺的显式固化。

系统的复杂性来自两个方面:状态空间的无穷膨胀,依赖关系的无限延伸。单元测试的价值,在于以最小可控单元为边界,在状态空间和依赖网络中锚定出一条确定的行为路径

这条路径的意义不在当下,而在未来:

单元测试不证明代码正确,它证明的是代码曾经正确过,以及在什么前提下正确

这种对"前提条件"的显式表达,才是单元测试作为知识载体的核心价值。它告诉后来的维护者:这个函数在什么输入下、产生什么输出、依赖什么外部条件、修改什么内部状态。

结语

单元测试的实质,是将行为假设转化为可验证事实的工程化手段。

它要求开发者:

关联内容(自动生成)