100%代码覆盖率不等于没有Bug,也不代表重构安全;最危险的反模式是无断言测试——执行了代码却未验证行为,导致逻辑错误无法被发现。

代码覆盖率在 JS 项目里常被当作质量“护身符”,但实际中它很容易失真——覆盖率高不等于没 bug,更不等于重构安全。真正要规避的,是那些让覆盖率数字好看、却对工程健康毫无帮助的反模式。
无断言测试:覆盖了代码,没验证行为
这是最危险也最常见的反模式。测试执行了函数,但没检查返回值、没断言副作用、甚至没调用 assert。Jest 报告里整行绿色,可逻辑错得离谱也不会报错。
- 检查每个测试用例是否至少含一个 assert 或 expect 断言,拒绝只调用不验证的“空跑”测试
- 在 CI 中启用 --detectOpenHandles 和 --forceExit,防止测试因未清理异步操作而“假成功”
- 对计算类函数(如折扣、格式化、校验),必须覆盖边界输入(空值、极值、非法类型)并断言输出
分支覆盖缺失:语句全绿,逻辑半瘫
一个 if (a && b) { ... } else if (a || b) { ... },只测 a=true,b=true 和 a=false,b=false,就能拿下 100% 行覆盖,但 a=false,b=true 这个关键分支压根没走——bug 就藏在这里。
- 打开 Jest + Istanbul 的 HTML 报告,重点筛选 % Branch 明显低于 % Lines 的文件
- 逐个点击标红的
if/else、switch、三元表达式,补全缺失分支的测试用例 - 对复合条件,用 条件覆盖 思维拆解:确保每个子条件的 true/false 组合都被触发过
死代码误判:覆盖率低≠该删,高≠可信任
Chrome DevTools Coverage 面板标红的代码,未必是包袱;而 nyc 报告里覆盖率达标的模块,也可能长期没人维护、依赖腐烂、逻辑僵化。
- 标红 ≠ 立刻删:先确认是否属于用户路径未触达(如后台管理页、灰度功能开关),再决定移除或懒加载
- 高覆盖 ≠ 可信:对函数覆盖 100% 但语句覆盖仅 40% 的模块,说明大量逻辑被包裹在未执行分支里,需人工审查判断是否废弃
- 结合 git blame 和 import 图谱,优先处理“覆盖低 + 修改少 + 依赖多”的高危陈旧模块
测试绑定实现细节:一改就挂,不是保护是枷锁
用 jest.mock 深度打桩内部方法,用 verify 断言私有函数调用次数,这类测试不是在保行为,是在给当前写法上锁。
- 只 mock 外部依赖(API、Storage、第三方 SDK),不 mock 同一模块内的函数调用
- 断言聚焦输入 → 输出、状态变更、事件触发,而非“第 3 行调用了哪个 helper”
- 重构前先问:这个测试失败时,用户能感知到功能异常吗?不能,就重写











