我的 代码覆盖率 入门之旅

一、什么是代码覆盖率?

代码覆盖率测试 核心:

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

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


二、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 源码的覆盖率测试就是一个 "插桩 → 运行 → 收集 → 报告" 的自动化过程,帮助你用科学的数据衡量测试的完备性,而不是盲目猜测。

相关推荐
葡萄城技术团队9 分钟前
【SpreadJS V18.2 新版本】设计器新特性:四大主题方案,助力 UI 个性化与品牌适配
前端
lumi.19 分钟前
Swiper属性全解析:快速掌握滑块视图核心配置!(2.3补充细节,详细文档在uniapp官网)
前端·javascript·css·小程序·uni-app
调皮LE21 分钟前
可放大缩小弹窗组件,基于element-ui的vue2版本
前端
陈随易24 分钟前
10年老前端,分享20+严选技术栈
前端·后端·程序员
我的小月月29 分钟前
基于Canvas实现的网页取色器功能解析
前端
芝士加43 分钟前
还在用html2canvas?介绍一个比它快100倍的截图神器!
前端·javascript·开源
阿虎儿44 分钟前
React 引用(Ref)完全指南
前端·javascript·react.js
Ratten1 小时前
解决 error when starting dev server TypeError crypto$2.getRandomValues
前端
coding随想1 小时前
深入浅出DOM3合成事件(Composition Events):如何处理输入法编辑器(IME)的复杂输入流程
前端
六月的雨在掘金1 小时前
狼人杀法官版,EdgeOne 带你轻松上手狼人杀
前端·后端