Angular 代码覆盖率完整指南:从 `ng test --coverage` 到覆盖率门禁强制与高级配置
导读
代码覆盖率报告用于揭示代码库中那些尚未被单元测试充分覆盖的部分。对于使用 Angular CLI(基于 Vitest 的 @angular/build:unit-test builder)的开发者来说,覆盖率不只是事后统计——它可以通过阈值(thresholds)作为构建门禁,让 CI 在覆盖率低于团队约定标准时直接让测试失败。本文从 @vitest/coverage-v8 安装、ng test --coverage 报告生成,到 angular.json 中的 coverageThresholds、coverageInclude/Exclude、coverageReporters 与 coverageWatermarks 逐项展开,并对照仓库内的 单元测试总览、Karma 迁移指南 与 Karma 测试指南 解释其底层运行方式,帮你把“测了没”落实为“测了多少、是否达标、如何强制达标”。
本文以 Angular 代码覆盖率官方文档 为骨架。该指南描述的是新 Angular CLI 项目的默认测试体系(Vitest,builder 为
@angular/build:unit-test)。如果你仍在使用 Karma,可参考 Karma 测试指南,其覆盖率强制方式不同(详见下文)。
前置条件:安装 @vitest/coverage-v8
Vitest 本身不带覆盖率引擎。要基于 Vitest 生成代码覆盖率报告,必须先以开发依赖(devDependency)的形式安装官方配套的 V8 覆盖率包 @vitest/coverage-v8。它基于 V8 引擎内置的代码覆盖率数据(即浏览器/Node 的 v8 profiling 能力),在执行测试时收集每条语句、分支、函数与行的执行计数,具有较低的性能开销和较准确的统计结果。
在项目根目录按所使用的包管理器执行对应的安装命令:
# npm
npm install --save-dev @vitest/coverage-v8
# yarn
yarn add --dev @vitest/coverage-v8
# pnpm
pnpm add -D @vitest/coverage-v8
# bun
bun add --dev @vitest/coverage-v8
背景知识:在仓库的 单元测试总览 中说明,Angular CLI 会为你下载并安装测试所需的全部依赖,新项目默认自带 vitest 与 jsdom;Vitest 在 Node.js 环境中运行单元测试,并通过 jsdom(可替换为 happy-dom)模拟浏览器 DOM,以省去启动真实浏览器的开销。@vitest/coverage-v8 则是这一体系之外唯一需要你显式追加安装的覆盖率依赖——--coverage 标志只负责开启统计与生成,报告引擎本体必须提前就位。
生成覆盖率报告:ng test --coverage
依赖就绪后,只需在常规测试命令后追加 --coverage 标志:
ng test --coverage
执行流程说明:
ng test会以 watch 模式(监听模式) 构建应用并启动 Vitest 测试运行器(在交互式终端且非 CI 环境下默认开启 watch,持续监听文件改动并重跑测试);- 由于带上了
--coverage,本轮运行结束时会额外执行覆盖率统计; - 测试全部完成后,命令会在项目目录下新建一个
coverage/目录,并把报告写入其中。
打开 coverage/ 目录下的 index.html 文件,即可看到一份可交互的报告页面:左侧是按目录/文件组织的源码树,点击任意文件可展开逐行的覆盖视图,报告中同时给出全局与每个文件的覆盖率数值。
CI 场景提示:若希望在 CI 上单次运行,可参考 单元测试总览 中的做法——多数 CI 服务器会设置 CI=true 环境变量,ng test 检测到后会自行切换到非交互的单次运行模式;若服务器未设置该变量,也可用 ng test --no-watch --no-progress 强制单次执行。
让覆盖率默认开启
--coverage 是命令行开关;如果你想在每次测试时都自动生成覆盖率报告,则无需每次敲命令,直接在 angular.json 的项目 test target 中把 coverage 选项设为 true 即可:
{
"projects": {
"your-project-name": {
"architect": {
"test": {
"builder": "@angular/build:unit-test",
"options": {
"coverage": true
}
}
}
}
}
}
在 单元测试总览 的 angular.json 选项清单中,coverage 的默认值为 false,其作用是“开启或关闭代码覆盖率报告的布尔开关”。需要注意,coverage 只是允许生成报告,并不会对测试结果产生“不达标即失败”的约束——那正是下文 coverageThresholds 的职责。
强制覆盖率阈值:让“不达标”直接失败
覆盖率百分比用来估算代码库被测试覆盖的程度。团队一旦约定“单元测试的最低覆盖率”,就可以把它固化进配置,让测试命令在覆盖率跌破该下限时执行失败——这样 CI 流水线也会随之阻断,防止覆盖率悄悄滑坡。
例如,你希望代码库的覆盖率始终不低于 80%(语句、分支、函数、行四条维度同时达标),在 angular.json 中为 test target 的 options 添加 coverageThresholds:
{
"projects": {
"your-project-name": {
"architect": {
"test": {
"builder": "@angular/build:unit-test",
"options": {
"coverage": true,
"coverageThresholds": {
"statements": 80,
"branches": 80,
"functions": 80,
"lines": 80
}
}
}
}
}
}
}
coverageThresholds 下四个维度对应的含义分别是:
| 维度 | 含义 | 建议取值策略 |
|---|---|---|
statements |
语句覆盖率,被执行到的语句占全部语句的比例 | 三者中通常最“宽松”,是常见起步阈值 |
branches |
分支覆盖率,if/else、switch、三元、逻辑短路等路径是否都被走到 |
往往最难拉高,也最能暴露遗漏场景 |
functions |
函数覆盖率,被调用过的函数占全部函数的比例 | 反映公共/私有方法是否均有用例覆盖 |
lines |
行覆盖率,被执行过的代码行数占比 | 与 statements 接近,常一起设限 |
配置后,当运行测试时覆盖率跌破任一维度的 80%,命令就会失败,并在输出中给出各维度实际覆盖率与差值,便于定位缺口。
与 Karma 时代的差异:在旧体系(Karma + karma-coverage)中,阈值强制是在 karma.conf.js 的 coverageReporter.check 中配置的。仓库中的 Karma 测试指南 展示过对应写法——在 coverageReporter 中设置 dir 输出目录并借助 check 属性声明最低覆盖率,不满足时同样令测试运行失败。而当前文档描述的是 Vitest 体系的统一做法:所有覆盖率相关配置都收敛在 angular.json 的 test.options 内,无需再维护独立的 reporter 配置。
高级配置:包含排除、报告器与水印着色
除阈值外,angular.json 的 test.options 还支持四类覆盖率相关选项:
coverageInclude:Glob 模式数组,指定要纳入覆盖率统计的文件集合(例如只统计src/app下的业务代码)。覆盖率统计默认依据测试的 import 图,但显式 include 有助于排除工具脚本、接口类型等不希望计入分母的文件。coverageExclude:Glob 模式数组,指定要从覆盖率报告中排除的文件(例如**/main.ts、**/*.mock.ts、第三方 polyfill 等)。常与coverageInclude配合,先把范围锁定到业务目录,再把个别已知不受测的文件剔除,从而得到更诚实、可解释的覆盖率口径。coverageReporters:报告器数组,决定以哪些格式输出报告。常见取值包括:html:浏览器可交互报告,覆盖到行/分支着色,适合本地coverage/index.html人工浏览;lcov:LCOV 格式,附带行级明细与摘要,是 SonarQube、Coveralls 等代码质量平台的通用输入格式;json:结构化数据,便于脚本解析或在 CI 中做自定义聚合与趋势存档;- 此外还支持如
text、text-summary、clover、cobertura等 Vitest/istanbul 生态常见格式。
coverageWatermarks:为 HTML 报告器 指定[low, high]两组水印,作用是控制报告的颜色编码。覆盖率低于low时显示红色、介于low与high之间为黄色、达到或超过high后显示绿色,让“健康程度”一目了然。
将上述选项组合写入 angular.json 的完整示例:
{
"projects": {
"your-project-name": {
"architect": {
"test": {
"builder": "@angular/build:unit-test",
"options": {
"coverage": true,
"coverageReporters": ["html", "lcov"],
"coverageWatermarks": {
"statements": [50, 80],
"branches": [50, 80],
"functions": [50, 80],
"lines": [50, 80]
}
}
}
}
}
}
}
这个示例同时生成 html 与 lcov 两种报告(前者供开发者本地查看,后者交给 CI 质量平台),并把四条覆盖率维度的水印统一设为“50% 以下红、50%–80% 黄、80% 以上绿”。需要注意的是,watermarks 只影响 HTML 报告的视觉编码,与 coverageThresholds 的“不达标即失败”语义相互独立——前者是展示辅助,后者才是质量门禁。
可选的进一步定制:如果你需要超出上述选项的细粒度控制,迁移指南 指出可通过 test.options.runnerConfig 指向自定义的 vitest.config.ts(或设为 true 自动查找共享的 vitest-base.config.*),在 Vitest 层面叠加 coverage.provider、coverage.reporter 等更底层配置;但该指南也明确提示:CLI 为保证正确运行会覆盖 test.projects、test.include 等属性,且 Angular 团队不对自定义配置文件内容与其中第三方插件提供直接支持。
与整个 Angular 测试体系的关系
理解代码覆盖率配置在仓库测试体系中的位置,有助于判断配置的生效范围与迁移语义:
- 配置入口统一:当前默认测试体系的所有测试相关设置均收敛于
angular.json的testtarget(builder 为@angular/build:unit-test)。迁移指南 明确写道:“代码覆盖率是 Angular CLI 中的一等公民特性,可直接通过ng test --coverage启用”,无需再像 Karma 时代那样安装并接线karma-coverage。 - CLI 代为构建 Vitest 配置:据 迁移指南 的“Configuration”章节,Angular CLI 会根据
angular.json的 options 在内存中拼装完整的 Vitest 配置,而不是让用户手写散落各处的配置文件——因此coverage、coverageThresholds、coverageReporters、coverageWatermarks、coverageInclude/Exclude这些选项才会以 JSON 结构出现在test.options中并直接生效。 - 默认不开启、目录固定:
coverage默认false,开启后产物默认落在项目根目录的coverage/,其中index.html为 HTML 报告器的主入口(单元测试总览 同样将报告目录描述为coverage/)。 - 与 CI 结合的自然链路:覆盖率报告为 HTML 供人工查阅、为 LCOV/JSON 供平台聚合;阈值强制则在测试命令这一层保证“覆盖不足即失败”,两者共同支撑起“提交即校验”的工程实践。
小结与常见疑问速查
| 需求 | 配置位置 | 关键点 |
|---|---|---|
| 跑一次覆盖率 | 命令行 | ng test --coverage,产物在 coverage/index.html |
| 每次测试都出报告 | test.options.coverage |
设为 true(默认 false) |
| 覆盖率不足就让测试失败 | test.options.coverageThresholds |
四维 statements/branches/functions/lines,低于阈值即失败 |
| 只统计/剔除某些文件 | test.options.coverageInclude / coverageExclude |
使用 Glob 模式数组 |
| 指定输出格式 | test.options.coverageReporters |
如 ["html", "lcov", "json"] |
| 调整 HTML 报告红黄绿阈值 | test.options.coverageWatermarks |
[low, high] 水印,仅影响视觉着色 |
| 需要 Vitest 更底层选项 | test.options.runnerConfig |
指向自定义 vitest.config.ts,注意 CLI 会覆盖部分属性 |
| 仍在用 Karma | Karma 测试指南 | 阈值写在 karma.conf.js 的 coverageReporter.check |
实践中建议的落地顺序:先安装 @vitest/coverage-v8 并执行一次 ng test --coverage 得到基线;接着用 coverageExclude/coverageInclude 校准统计口径,避免把非业务脚手架算进分母;随后参考报告把薄弱模块补齐用例;最后在 angular.json 中写入 coverageThresholds 与 CI 结合,让 80%(或团队自定义值)成为可自动强制执行的团队约定。需要理解更多测试上下文时,可继续阅读 单元测试总览、服务测试 与 组件测试基础 等配套文档。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00