首页
/ Angular 项目使用 Karma 与 Jasmine 进行单元测试:配置、覆盖率门槛、CI 运行与浏览器调试完整指南

Angular 项目使用 Karma 与 Jasmine 进行单元测试:配置、覆盖率门槛、CI 运行与浏览器调试完整指南

2026-09-07 18:28:37作者:柯茵沙

Karma 是一款被广泛使用的测试运行器(Test Runner),配合 Jasmine 测试框架,曾长期是 Angular CLI 默认的单元测试技术栈。随着 Vitest 成为新项目的默认测试运行器,Karma 依旧是受官方支持、存量项目中非常普及的选项。本文基于 Angular 官方文档中的《Testing with Karma and Jasmine》测试指南,结合本仓库内的真实配置与源码证据,系统讲解如何在 Angular 应用中从零配置 Karma + Jasmine、运行与调试测试、落地覆盖率门槛,并在 CI 中以无头浏览器稳定执行测试。读完本文,你将掌握一套可直接复制到实际项目中的完整 Karma 单元测试工作流。

在开始前先明确一个概念边界:Karma 是测试运行器(负责启动浏览器、加载被测代码与测试文件、收集并汇报结果),Jasmine 是测试框架(提供 describeitexpect 等断言与用例组织语法)。两者分工不同,日常口中所说的“Karma 测试”实际上通常是这套"Karma 运行器 + Jasmine 框架"组合。

Karma + Jasmine 在当前 Angular 技术栈中的定位

从本仓库维护的文档与路线图可以看到清晰的演进脉络:

  • 新项目的默认单元测试运行器已是 Vitest,相关说明见 testing/overview.mdreference/roadmap.md,其中明确指出 Vitest 已成为 Angular 的主要测试运行器,团队正在推动将“Karma 迁移至 Vitest”的实验性工具走向稳定;
  • 与此同时,Karma 仍然是一款受支持且被广泛使用的运行器,大量存量项目依旧依赖 Karma + Jasmine;
  • 本仓库的文档站应用 adev 自身的 test 目标就是一个活生生的真实案例——它没有使用 Vitest,而是在新的统一 @angular/build:unit-test builder 下显式指定 runner: "karma"

查看 adev/angular.json 可看到该目标的完整写法:

"test": {
  "builder": "@angular/build:unit-test",
  "options": {
    "runner": "karma",
    "browsers": ["ChromeHeadlessNoSandbox"],
    "include": ["src/app/**/*.spec.ts"]
  }
}

这个例子恰好验证了本文要讲解的两点核心知识:Karma 已被收编到统一的 unit-test builder 下,通过 runner 选项切换运行器;同时测试文件约定使用 *.spec.ts 命名并通过 include 圈定。

搭建 Karma 与 Jasmine

Karma + Jasmine 既可以随新项目一键初始化,也可以手动添加到既有项目中。

新建项目:一条命令完成预配置

使用 Angular CLI 的 ng new 时,通过 --test-runner=karma 选项即可生成带好 Karma 与 Jasmine 完整配置的项目:

ng new my-karma-app --test-runner=karma

adev/src/content/cli/new.json 中对 test-runner 选项的官方描述即为"The unit testing runner to use",说明该选项正是用来在脚手架阶段选定单元测试运行器。

既有项目:三步手动接入

如果项目已经存在,可按以下三个步骤把 Karma + Jasmine 补进来。

步骤 1:安装依赖包

根据你使用的包管理器选择对应命令:

npm install --save-dev karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter jasmine-core @types/jasmine yarn add --dev karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter jasmine-core @types/jasmine pnpm add -D karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter jasmine-core @types/jasmine bun add --dev karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter jasmine-core @types/jasmine

各包职责如下:

  • karma:测试运行器本体;
  • karma-jasmine:Karma 与 Jasmine 框架的适配插件;
  • karma-chrome-launcher:负责启动 Chrome / ChromeHeadless 浏览器执行测试的启动器;
  • karma-coverage:基于 Istanbul 的覆盖率采集插件(本仓库 adev 侧使用的 karma 模板中引用的正是它);
  • karma-jasmine-html-reporter:在浏览器中以可视化的 Jasmine Spec Runner 呈现测试结果;
  • jasmine-core:Jasmine 框架本体;
  • @types/jasmine:为 TypeScript 提供 describeitexpect 等全局 API 的类型声明。

步骤 2:在 angular.json 中把测试运行器切换为 Karma

找到 architect.test 目标,确保 builder@angular/build:unit-test,并在 options 中设置 runner: "karma"

{
  // ...
  "projects": {
    "your-project-name": {
      // ...
      "architect": {
        "test": {
          "builder": "@angular/build:unit-test",
          "options": {
            "runner": "karma"
            // ... other options
          }
        }
      }
    }
  }
}

若你的项目仍在使用旧的 @angular/build:karma 专用 builder,可参考迁移说明进行调整(详见 migrating-to-vitest.md 中对新旧 builder 差异的说明:旧 builder 允许在 test 目标内直接配置 polyfillsassetsstyles 等构建选项,而统一的 unit-test builder 不再支持,这些选项需收敛到 build 目标,测试默认复用 development 构建配置,tsConfig 默认指向 tsconfig.spec.json)。

步骤 3:在 tsconfig.spec.json 中加入 Jasmine 类型

为了让 TypeScript 在编写测试时识别全局测试函数 describeit 等,需要在 tsconfig.spec.jsoncompilerOptions.types 中显式加入 "jasmine"

{
  // ...
  "compilerOptions": {
    // ...
    "types": ["jasmine"]
  }
}

这里用 types 数组显式收窄全局类型来源,能避免把 @types/* 下所有包自动注入全局作用域,是 Angular 官方推荐的规范写法。

运行测试

配置完成后,即可通过 ng test 命令执行测试:

ng test

ng test 会以 watch(监听)模式构建应用,并启动 Karma 测试运行器。构建完成后,控制台输出与下面类似:


02 11 2022 09:08:28.605:INFO [karma-server]: Karma v6.4.1 server started at http://localhost:9876/
02 11 2022 09:08:28.607:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
02 11 2022 09:08:28.620:INFO [launcher]: Starting browser Chrome
02 11 2022 09:08:31.312:INFO [Chrome]: Connected on socket -LaEYvD2R7MdcS0-AAAB with id 31534482
Chrome: Executed 3 of 3 SUCCESS (0.193 secs / 0.172 secs)
TOTAL: 3 SUCCESS

解读这段日志的关键信息:

  • Karma 服务默认监听 http://localhost:9876/,浏览器与该服务建立 socket 连接后开始执行用例;
  • 逐行阅读可见 Karma 的完整生命周期:karma-server 启动 → launcher 以"并发数不限"策略启动 Chrome → Chrome 连接成功 → 汇总 "Executed 3 of 3 SUCCESS" → 输出 TOTAL

Karma 会额外在浏览器窗口中展示交互式测试结果(由 karma-jasmine-html-reporter 驱动,见仓库 karma.conf.js 模板中的 jasmineHtmlReporter 配置):

浏览器中 Jasmine HTML Reporter 的测试结果界面

  • 点击某一条测试用例所在行,可只重新运行该用例;
  • 点击某个 describe 描述(测试分组/测试套件),可只重跑该分组内的所有用例。

与此同时 ng test 一直在监听文件变化:当你改动任意源文件并保存后,测试会立刻重新执行,浏览器自动刷新并展示最新结果——这正是 watch 模式下"改代码 → 跑测试 → 看结果"的高频反馈循环。

一个典型的 Karma + Jasmine 用例由 describe(分组)、it(单条用例)与 expect(断言)构成,组件级测试还会用到 TestBed.createComponent() 创建组件夹具,例如(来自 components-basics.md 的最小用例):

describe('Banner (minimal)', () => {
  it('should create', () => {
    const fixture = TestBed.createComponent(Banner);
    const component = fixture.componentInstance;
    expect(component).toBeDefined();
  });
});

深度配置:理解 karma.conf.js

Angular CLI 会替你打理 Jasmine 与 Karma 的大部分配置:它基于 angular.json 中的选项,在内存中构造完整配置,无需显式配置文件即可运行。但当默认行为不满足需求时,可以生成一份自定义配置。

生成 karma.conf.js

在项目根目录执行:

ng generate config karma

即可生成 karma.conf.js,Angular CLI 之后会加载并合并其中自定义的内容。

karma.conf.js 关键字段逐项解读

本仓库维护的 karma.conf.js 模板 是官方新项目脚手架的完整写照,逐段拆解如下:

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage'),
      require('@angular-devkit/build-angular/plugins/karma'),
    ],
    client: {
      jasmine: {
        // 可在此添加 Jasmine 配置
        // 例如 random: false 关闭随机执行顺序,seed: 4321 固定随机种子
      },
      clearContext: false, // 让 Jasmine Spec Runner 输出常驻浏览器,便于反复查看
    },
    jasmineHtmlReporter: {
      suppressAll: true, // 移除重复的失败堆栈输出
    },
    coverageReporter: {
      dir: require('path').join(__dirname, './coverage/example-app'),
      subdir: '.',
      reporters: [{type: 'html'}, {type: 'text-summary'}],
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    restartOnFileChange: true,
  });
};

字段含义与影响:

字段 含义与建议值
basePath 所有相对路径解析的根目录,默认空字符串即配置文件所在目录
frameworks 声明使用的框架插件;固定为 ['jasmine', '@angular-devkit/build-angular'],后者负责把 Angular 编译产物桥接给 Karma
plugins 显式列出加载的 Karma 插件;若项目使用旧版,模板中该处可能为 karma-coverage-istanbul-reporter(见本仓库 integration/cli-hello-world/karma.conf.js),新版已迁移至 karma-coverage
client.jasmine 向 Jasmine 透传的配置:可用 random: false 关闭随机用例执行顺序,或用 seed: 4321 固定随机种子以复现特定顺序下的失败
client.clearContext 设为 false 时保留 Spec Runner 输出在浏览器中,便于失败后查看
jasmineHtmlReporter.suppressAll 抑制 HTML Reporter 中重复的输出轨迹
coverageReporter 覆盖率产物目录与报告类型,常见为 html + text-summary
reporters 控制台与浏览器报告器,['progress', 'kjhtml'] 为默认组合
port Karma 服务端口,默认 9876
autoWatch 是否监听文件变化自动重跑,开发期应为 true
browsers 执行测试的浏览器,开发用 Chrome,CI 用 ChromeHeadless
singleRun 是否为单次运行;开发 watch 期为 false,CI 应配合 --no-watch 语义一次跑完退出
restartOnFileChange 文件变化时重启整个浏览器实例(比增量重跑更干净)

仓库中的集成测试项目还展示了为 CI 定制无头浏览器启动器的做法(integration/cli-hello-world/karma.conf.js),在容器/CI 环境下用 ChromeHeadless 加参数绕开沙箱限制:

customLaunchers: {
  ChromeHeadlessNoSandbox: {
    base: 'ChromeHeadless',
    flags: [
      '--no-sandbox',
      '--headless',
      '--disable-gpu',
      '--disable-dev-shm-usage',
      '--hide-scrollbars',
      '--mute-audio',
    ],
  },
},
browsers: ['ChromeHeadlessNoSandbox'],

这一点恰好呼应了本文前面引用的 adev/angular.json:官方文档站自身的测试目标在浏览器选择上同样使用了 ChromeHeadlessNoSandbox

通过 angular.json 与 runner-config 精细控制

cli/test.jsonng test 命令的选项定义可以归纳出,unit-test builder 在 Karma 场景下还提供以下常用选项:

  • runner:指定测试运行器,取 karmavitest
  • runner-config:指定所选运行器的配置文件路径;传字符串作为配置文件路径,传 true 时自动搜索默认配置文件(例如 karma.conf.js),传 false 时不加载任何外部配置文件;
  • code-coverage:开启覆盖率报告;未指定时会回退使用运行器配置文件中的覆盖率配置;
  • browsers / include 等:控制执行浏览器与纳入测试的 *.spec.ts 文件范围。

需要特别留意 --headless 这一选项在 cli/test.json 中有明确说明:Karma 运行器不支持该选项——无头模式应通过把 browsers 配置为 ChromeHeadless(或自定义 ChromeHeadlessNoSandbox)来实现,而非传 --headless 标志。

覆盖率门槛强制校验

要让"测试跑完并通过"不足以代表质量,可以设置最低代码覆盖率:未达标即让本次测试失败。在 karma.conf.jscoverageReporter 段使用 check 属性即可实现。

例如,要求全局语句、分支、函数、行四个维度覆盖率均不低于 80%:

coverageReporter: {
  dir: require('path').join(__dirname, './coverage/<project-name>'),
  subdir: '.',
  reporters: [
    { type: 'html' },
    { type: 'text-summary' }
  ],
  check: {
    global: {
      statements: 80,
      branches: 80,
      functions: 80,
      lines: 80
    }
  }
}

要点说明:

  • dir 使用 require('path').join(__dirname, ...) 拼出基于项目根目录的绝对输出路径,<project-name> 需替换为实际项目名;
  • subdir: '.' 让各类报告直接输出到 coverage/<project-name>,避免默认按浏览器维度再套一层子目录;
  • reporters 中的 html 用于生成可交互的网页报告,text-summary 用于在控制台输出汇总行;
  • check.global 定义全局最低阈值,四个指标可分别设置;一旦实际覆盖率低于阈值,Karma 会让测试运行以失败结束。除此之外还可针对每个文件(each)单独设限,适合对关键模块施加强约束。

开启覆盖率统计可在运行测试时追加 ng test --code-coverage。关于覆盖率工作流的更多实操细节(包括如何开启与查看报告),可继续阅读 code-coverage.md

在持续集成(CI)中运行 Karma

在 CI 环境中没有图形界面、也不需要持续监听,应使用一次性无头运行:

ng test --no-watch --no-progress --browsers=ChromeHeadless

三个标志各有不可替代的作用:

  • --no-watch:跑完一轮即退出,避免进程因 watch 永不结束导致 CI 任务挂起;
  • --no-progress:关闭逐条进度输出,避免 CI 日志被刷屏、也减少终端缓冲负担;
  • --browsers=ChromeHeadless:在无图形界面的 CI 机器上以 Chrome 无头模式执行。若 CI 运行在容器中(例如 Jenkins/Docker),往往还需要配合前文介绍的 ChromeHeadlessNoSandbox 启动器(--no-sandbox 等 flags),这正是仓库 integration 各项目 karma.conf.js 中封装自定义 launcher 的动机。

在浏览器中调试失败用例

测试行为不符合预期时,可以直接在浏览器里单步调试。由于 Karma 用例运行在真实浏览器中,调试体验与调试应用代码一致。

调试步骤:

  1. 找到 Karma 打开的浏览器窗口(若它未自动弹出,可先参考测试环境搭建说明,见 testing/overview.md,确保测试已能正常跑起来);
  2. 点击浏览器页面上的 DEBUG 按钮,Karma 会打开一个新标签页并重新执行测试;
  3. 打开浏览器的开发者工具(Windows 按 Ctrl-Shift-I,macOS 按 Command-Option-I);
  4. 切换到 Sources 面板;
  5. Control/Command-P,输入测试文件名快速打开对应的 spec 文件;
  6. 在测试代码中打上断点;
  7. 刷新浏览器,即可看到执行停在你设置的断点上,随后可逐行观察变量与调用栈。

下图示意了打断点后的调试现场——可看到测试停在了 spec 中的断言位置,右侧为作用域与调用栈信息:

在 Karma 打开的浏览器中调试测试断点

补充两点实用技巧:由于 Karma 默认会缓存编译产物,调试改完代码后记得刷新浏览器标签让最新版本生效;若想聚焦调试某条用例,可先在 Jasmine Spec Runner 页面点击对应用例行单独重跑,减少噪音。更系统的调试指引还可参考 debugging.md

更多相关资源

如果你是在维护一个 Karma + Jasmine 的存量项目、想评估后续演进方向,以下仓库内文档可以衔接阅读:

  • 组件测试基础TestBedComponentFixturefakeAsync 等组件测试核心 API 的完整讲解;
  • 代码覆盖率指南:覆盖率开启、报告与门槛设置的进阶说明;
  • 从 Karma 与 Jasmine 迁移到 Vitest:当存量项目需要切换到 Vitest 时,介绍自动化重构 schematic、angular.json 改造与运行器配置差异,可作为本文的自然延伸。

小结:Karma + Jasmine 仍是 Angular 生态中成熟、稳定且受官方支持的单元测试组合。本文从新项目脚手架与存量项目迁移两个入口梳理了完整接入流程,并结合本仓库真实的 angular.jsonkarma.conf.js 与 CLI 选项定义,详解了 runnerrunner-config、覆盖率门槛、CI 无头执行与浏览器调试等核心实践。掌握这套工作流后,你可以在任何 Angular 项目中快速落地可观测、可量化、可持续的单元测试基础设施。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391