单元测试应将类视为黑盒,仅测试 public 方法的输入输出是否符合契约;构造实例→调用方法→断言返回值或状态变更;不访问私有字段,不依赖不可控值,mock 外部依赖,覆盖边界与异常路径,命名与结构遵循 setup-action-assert 原则。

直接测试 class 的公开方法,不碰私有字段或内部实现细节,重点验证输入输出是否符合契约。
只测 public 方法,用 new 实例化后调用
class 单元测试的核心是把类当作黑盒:构造实例 → 调用方法 → 断言返回值或状态变更。不要试图 mock this 或访问 #private 字段,除非该字段本身被设计为可测试的接口(如 getter)。
- 每个 test 块只覆盖一个明确行为,比如 “调用 calculateTotal() 且 items 为空时应返回 0”
- 避免在测试中依赖 Date.now()、Math.random() 等不可控值;若 class 内部用了,需提前冻结或注入可控依赖
- 构造函数参数尽量传入简单值(字符串、数字、对象字面量),不传真实 DOM 节点或 fetch 实例
处理副作用:模拟依赖,不执行真实操作
如果 class 方法里调用了 API、localStorage 或第三方库,必须拦截它们。否则测试会变慢、不稳定,还可能污染本地环境。
- 用 jest.mock() 或 vi.mock() 替换模块导出,例如 mock 掉 class 里 import 的 apiClient
- 对实例方法做局部 mock:用 jest.spyOn(instance, 'methodName').mockImplementation(...) 控制某次调用的行为
- 写完测试后记得 mockClear() 或 restoreAllMocks(),防止测试间干扰
覆盖边界与异常路径,不只测“正常流程”
class 往往封装了校验、转换、组合等逻辑,容易在 null、undefined、空数组、超限数值等场景出错。这些不是边缘情况,而是高频真实输入。
- 显式测试构造函数传入非法参数时是否 throw Error(用 expect(() => new MyClass(invalid)).toThrow())
- 对返回 Promise 的方法,用 await expect(instance.asyncMethod()).resolves.toBe(...) 或 .rejects.toThrow(...)
- 验证 setter 是否正确更新内部状态,可通过公开 getter 或 toJSON() 辅助断言
命名清晰,结构分明:setup-action-assert 分三段
每个 test 名称要说明“什么条件下,发生什么,得到什么结果”。代码体用空行分隔初始化、执行、断言三部分,一眼看出意图。
- 推荐命名格式:“should [do X] when [given Y]”,例如 should return formatted date string when input is valid Date object
- setup 阶段只做最小必要初始化,比如 new Calculator({ precision: 2 })
- action 阶段只调用一次目标方法,不连写多个链式调用
- assert 阶段优先检查返回值,其次检查 this 上关键属性变化,最后才查 mock 调用次数











