单元测试倒逼团队写出更易测试的代码,天然偏好单一职责、依赖注入、纯函数和模块封装等设计模式;测试失败常暴露代码结构问题,推动服务层封装、函数拆分与副作用抽离;通过测试用例作为“活文档”固化模式约束,并融入CI流程自动拦截反模式。

单元测试本身不直接规定代码设计模式,但它能倒逼团队写出更易测试的代码,而可测试性天然偏好某些设计模式——比如单一职责、依赖注入、纯函数、模块封装。换句话说,写好单元测试的过程,就是在持续验证和塑造代码的设计质量。
用测试驱动设计:让模式自然浮现
当一个函数无法被干净地单元测试时,往往不是测试写得不好,而是代码结构出了问题。团队可以通过测试实践逐步收敛出合理的设计习惯:
- 测试失败提示“无法模拟网络请求” → 推动将 fetch 封装进可替换的服务层,引入依赖注入
- 测试发现一个函数要 mock 5 个内部状态才能跑通 → 暴露其违反单一职责,应拆分为 validate / format / save 等小函数
- 测试断言总因时间或随机值失败 → 倒逼把 Date.now()、Math.random() 等副作用抽离,改用可控参数传入
在测试中固化关键模式约束
通过测试用例本身作为“活文档”,明确哪些模式是团队约定的底线:
- 所有业务逻辑函数必须是纯函数:相同输入必得相同输出,不读写外部状态(可用 Jest 的
jest.mock()配合mockImplementation快速验证) - 组件/类必须支持依赖注入:构造函数或方法参数接受服务对象,而非直接 new 实例(测试时可传入 mock 对象)
- 模块对外只暴露最小接口:私有工具函数不导出,测试仅覆盖 public API(ESLint 规则 + 测试覆盖率报告可辅助检查)
把模式检查融入测试流程
不靠口头强调,而是让 CI 或本地 pre-commit 流程自动拦截反模式:
立即学习“Java免费学习笔记(深入)”;
- 用 Jest 的
test.todo标记“待重构函数”,强制后续提交需补全测试并满足拆分要求 - 配置 Istanbul 覆盖率阈值,要求核心模块单元测试覆盖率达 80%+;低覆盖率自动阻断 PR 合并,倒逼模块化与可测性提升
- 编写自定义 ESLint 插件规则(如禁止
new Date()直接调用),配合测试用例演示“正确写法”,形成闭环
测试不是贴在代码后面的标签,而是嵌入开发节奏里的设计反馈机制。坚持用测试去“问”代码:它能不能被独立验证?它的边界是否清晰?它的依赖是否可控?答案自然会引导团队走向更稳健的设计模式。


















