JS质量保障是环环相扣的实践闭环:单元测试为起点,覆盖率作标尺,CI卡点筑防线,规范与看板建长效机制;关键在真实暴露风险、驱动改进。

JS质量保障不是靠“跑通就提交”,而是一套环环相扣的实践闭环:单元测试是起点,覆盖率是标尺,CI卡点是防线,规范与看板是长效机制。关键不在堆高数字,而在让每个环节真实暴露风险、驱动改进。
单元测试要测什么、怎么写才有效
单元测试不是调用函数看输出,而是验证“给定输入 → 是否产生预期行为”。它必须满足三个硬性条件:
-
有明确断言:用
expect(...).toBe(...)或toThrow()等声明期望,拒绝“console.log后肉眼判断” -
完全隔离外部依赖:数据库、API、定时器、全局状态全部 mock;比如用
jest.mock('./api')拦截请求,用jest.useFakeTimers()控制 setTimeout -
一次只测一个关注点:方法名直述场景,例如
test('handles empty email input with validation error'),不写“test all cases”
边界和异常比正常流程更值得覆盖——calculateDiscount(100, 1.5) 应报错,formatName(null) 应不崩溃,这些才是线上高频故障点。
覆盖率指标不能只看总数,要分层盯关键维度
行覆盖率(lines)只是基础,真正暴露逻辑盲区的是分支(branches)和函数(functions)覆盖率:
-
分支覆盖率 ≥100%:确保每个
if/else、三元表达式、switch case都被执行,避免“只测了成功路径,漏掉失败降级” - 函数覆盖率 ≥95%:确认所有工具函数、校验方法、事件处理器都被调用,尤其警惕被 import 却从未执行的工具模块
- 增量覆盖率(diff coverage)才是卡点核心:CI 不应检查全量覆盖率,而应锁定本次 PR 修改的代码行,要求新增部分行覆盖 ≥90%、分支覆盖 ≥100%
例如,你改了 loginService.js 的权限判断逻辑,CI 报告会精准指出:“第42–45行未覆盖”,而不是笼统说“整体覆盖率跌到82%”。
把覆盖率检查嵌入开发全流程,而非事后补救
覆盖率只有在正确的时间点介入,才能真正起作用:
-
开发中:用
nyc --include=src/features/login npm test实时查看新功能模块的局部覆盖,配合 VS Code 插件高亮未覆盖行 -
提交前:Git hook 或 CI 脚本运行
c8 --check-coverage --lines 90 --branches 100 --include 'src/features/**',未达标直接阻断 - PR 时:Codecov 自动对比基线,标红“新增但未覆盖”的代码块,并阻止合并若核心模块覆盖率下降超 3%
- 长期维护:每周导出覆盖率最低的5个文件,列入技术债清单;将“新功能必须附带 ≥85% 行覆盖 + 100% 分支覆盖”写入《接入规范》
工具链要轻量可靠,避免配置黑洞
选型原则是“开箱即用、问题可定位、报告易解读”:
- 测试框架首选 Jest:零配置启动、内置 mock 和快照、覆盖率原生集成,覆盖 90% 场景无需额外插件
-
覆盖率工具用 c8(现代替代 nyc):基于 V8 引擎,速度更快、ESM 支持更好,
c8 npm test一条命令生成 HTML 报告 -
拒绝复杂抽象层:不封装自定义 test runner,不隐藏
--include或--exclude参数,让开发者随时能手动复现 CI 中的覆盖率计算逻辑
工具的价值在于降低写测试的摩擦,而不是增加理解成本。一个新人 clone 项目后,npm test 能立刻跑通并看到带颜色的覆盖率报告,这才是健康信号。


















