关键在于函数职责单一、依赖显式、副作用可控。应拆分复合操作为独立函数(如validateUser、normalizeUser等),通过参数注入外部依赖(saveFn、notifyFn、nowFn),优先使用纯函数,模块导出可测单元。

关键在于让函数职责单一、依赖清晰、副作用可控。高内聚不是靠堆逻辑实现的,而是靠“只做一件事”并把这件事做到底。
坚持单一职责,拆分复合操作
一个函数若同时校验、格式化、存储、通知,就难以单独验证其中任一环节。应拆成独立函数:
- validateUser:只检查必填字段和格式,返回布尔或错误对象
- normalizeUser:只处理大小写、空格、时间戳等格式转换
- saveUser:只调用数据库方法,不关心数据来源是否合法
- sendWelcomeEmail:只接收邮箱和姓名,不参与业务判断
这样每个函数都可被单独测试——输入确定,输出可断言,无需模拟整个流程。
显式声明依赖,避免隐式耦合
不要在函数内部直接调用 saveToDatabase 或 fetch 这类外部行为。改为通过参数传入:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 把数据库操作抽象为
saveFn函数参数 - 把邮件发送封装为
notifyFn,测试时传入jest.fn() - 时间相关逻辑用
nowFn = () => new Date()注入,便于控制时钟
依赖显式化后,测试时只需传入模拟函数,无需启动真实服务或修改全局状态。
优先使用纯函数处理数据
对输入无副作用、相同输入恒得相同输出的函数,天然适合单元测试:
- 像
sum(a, b)、capitalize(str)、filterByStatus(items, status)这类函数,不读写外部变量,不发请求,不改原数组 - 测试只需准备输入、断言输出,无需清理环境或重置状态
- 遇到非纯操作(如日期、随机数、DOM访问),用参数注入可控版本替代
模块边界清晰,导出可测单元
避免把逻辑藏在 IIFE 或未导出的闭包里。用 ES 模块导出核心函数:
- 导出
calculateDiscount而非只导出一个applyPromotion包裹函数 - 私有辅助函数如
isValidRate若逻辑关键,也建议导出供测试覆盖 - 模块默认导出对象时,确保属性是函数而非执行结果(避免导出
{ result: doWork() })
这样测试文件可直接 import { calculateDiscount } from './pricing.js',不依赖运行时环境。

















