我的 代码覆盖率 入门之旅

一、什么是代码覆盖率?

代码覆盖率测试 核心:

  • 哪些步骤被完全执行了?
  • 哪些步骤因为条件没达到被跳过了?
  • 哪些步骤甚至从来没被看过?

这个检查被使用了多少的过程,就是覆盖率分析。它能帮你发现多余的、没用的、或者永远走不到的死角步骤。


二、Vue 2 覆盖率测试的运行机制(流程图)

整个流程的核心是 "代码插桩" 。就像在每个步骤后面加上一个打卡器,小机器人每做完一步,就在相应的打卡器上"滴"一下,记录自己来过。

以下是完整的流程图和步骤解析:

  1. 源代码插桩

    • 工具 :使用 Istanbul (一个JS覆盖率工具)的插件(如 babel-plugin-istanbul)。
    • 过程 :在代码被打包(Webpack)或编译(Babel)之前,Istanbul 会遍历所有代码,并在每一个语句、分支、函数等位置注入一些"打卡"代码。转换后的代码不再是原始代码,而是被"插桩"后的代码。
  2. 执行测试

    • 工具Karma 测试运行器。它的作用是启动一个真实的浏览器(如 Chrome、Firefox),将插桩后的代码和你的测试用例加载到浏览器中执行。
    • 为什么用浏览器? 因为 Vue 是一个前端框架,需要在浏览器环境中运行,用 Node.js 模拟的(如 JSDOM)环境可能不够真实。
    • 你的测试代码(用 Mocha、Jasmine 等编写)会像用户一样操作和检查 Vue 组件。
  3. 收集覆盖率数据

    • 当测试用例在浏览器中执行被插桩的代码时,每一步"打卡"都会被记录。
    • 所有打卡结果会汇聚成一个包含覆盖率数据的全局对象,通常是 window.__coverage__
  4. 生成报告

    • 工具Istanbul 的命令行工具 nyc
    • 测试结束后,Karma 会将 window.__coverage__ 对象从浏览器中取出,并写入一个 coverage.json 文件。
    • nyc 命令会读取这个 JSON 文件,并生成各种格式(如 HTML、LCov)的、人类可读的覆盖率报告。
  5. 分析报告

    • 打开生成的 coverage/index.html 文件,你能看到一个非常详细的网页,清晰地展示了每个文件的覆盖率情况,甚至可以点击文件查看哪一行代码没有被执行到。

三、简单示例:看一个插桩前后的代码对比

假设我们有一段非常简单的 Vue 2 源码:

原始源码 (src/utils.js)

javascript 复制代码
export function isEven(num) {
  if (num % 2 === 0) {
    return true;
  } else {
    return false;
  }
}

被 Istanbul 插桩后的代码

Istanbul 会把它变成这样(已简化,便于理解):

scss 复制代码
import { increment } from "istanbul-lib-coverage";

// Istanbul 会创建一个全局的 coverage 对象来存储数据
const coverage = window.__coverage__ || (window.__coverage__ = {});
// 为这个文件创建一个计数器
coverage['src/utils.js'] = {
  statementMap: { /* 记录每个语句的位置信息 */ },
  fnMap: { /* 记录每个函数的位置信息 */ },
  branchMap: { /* 记录每个分支(if/else)的位置信息 */ },
  // 下面是核心:记录执行次数的计数器数组
  s: [0, 0, 0, 0], // 每个语句的计数器,初始为0
  f: [0], // 每个函数的计数器
  b: [[0, 0]] // 每个分支的计数器,if 和 else 各一个
};

export function isEven(num) {
  coverage['src/utils.js'].f[0]++; // 打卡:函数被调用了!
  coverage['src/utils.js'].s[0]++; // 打卡:第一行语句

  if (num % 2 === 0) {
    coverage['src/utils.js'].b[0][0]++; // 打卡:走了 if 分支
    coverage['src/utils.js'].s[1]++; // 打卡:return true 语句
    return true;
  } else {
    coverage['src/utils.js'].b[0][1]++; // 打卡:走了 else 分支
    coverage['src/utils.js'].s[2]++; // 打卡:return false 语句
    return false;
  }
}
coverage['src/utils.js'].s[3]++; // 打卡:函数定义后的结束语句

编写测试用例 (test/utils.spec.js)

javascript 复制代码
import { isEven } from '@/src/utils.js';

describe('isEven', () => {
  it('should return true for even numbers', () => {
    const result = isEven(2);
    expect(result).to.be.true; // 这个测试只会触发 if 分支
  });

  // 如果我们注释掉下面这个测试用例
  // it('should return false for odd numbers', () => {
  //   const result = isEven(1);
  //   expect(result).to.be.false; // 这个测试会触发 else 分支
  // });
});

运行测试并生成报告

  1. 用 Karma 运行测试后,Istanbul 会分析 window.__coverage__ 里的数据。

  2. 对于 src/utils.js 这个文件:

    • 函数覆盖率 :100% (isEven 函数被调用了)
    • 语句覆盖率:100% (所有语句都执行了)
    • 分支覆盖率50% (因为只走了 if 分支,else 分支没走!)

查看报告

你会在 HTML 报告里看到 else { return false; } 这一行被标为黄色粉色 ,表示这行代码被执行了,但所在的分支没有完全覆盖。如果你完全没测这个函数,那所有代码都会是红色


四、Vue 2 源码测试的特殊之处

对于 Vue 2 本身这个库,它的测试会更加复杂,但原理完全一样:

  1. 测试目标 :不再是业务组件,而是 Vue 的核心构造函数响应式系统虚拟DOM Diff 算法编译器等。
  2. 测试用例 :它们会直接调用 new Vue({...}),或者调用 Vue.compile(...) 等方法,然后断言其行为是否正确。
  3. 高覆盖率:像 Vue 这样的核心库,对覆盖率要求极高(通常保持在 99% 以上),确保每一个微小的功能变更都不会引起未知的崩溃。

总结

步骤 工具 目的 比喻
1. 插桩 babel-plugin-istanbul 在源代码中注入"打卡"代码 给食谱的每一步装上打卡器
2. 运行 Karma 在真实浏览器环境中运行测试 让烘焙小机器人按食谱操作
3. 收集 karma-coverage 收集浏览器中的 __coverage__ 数据 收集所有打卡器的记录
4. 报告 nyc 生成可读的覆盖率报告(HTML) 生成一份报告,显示哪些步骤没做

所以,Vue 2 源码的覆盖率测试就是一个 "插桩 → 运行 → 收集 → 报告" 的自动化过程,帮助你用科学的数据衡量测试的完备性,而不是盲目猜测。

相关推荐
于慨19 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz19 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
从前慢丶19 小时前
前端交互规范(Web 端)
前端
CHU72903519 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing19 小时前
Page-agent MCP结构
前端·人工智能
王霸天19 小时前
💥别再抄网上的Scale缩放代码了!50行源码教你写一个永不翻车的大屏适配
前端·vue.js·数据可视化
小领航20 小时前
用 Three.js + Vue 3 打造炫酷的 3D 行政地图可视化组件
前端·github
@大迁世界20 小时前
2026年React大洗牌:React Hooks 将迎来重大升级
前端·javascript·react.js·前端框架·ecmascript
PieroPc20 小时前
一个功能强大的 Web 端标签设计和打印工具,支持服务器端直接打印到局域网打印机。Fastapi + html
前端·html·fastapi
悟空瞎说20 小时前
深入 Vue3 响应式:为什么有的要加.value,有的不用?从设计到源码彻底讲透
前端·vue.js