Jest | 测试框架实战之-coverage命令实现原理

「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

前两天已经实现了Jest测试框架的环境搭建、基本测试用例的编写以及怎么解读测试覆盖率,没接触的建议去看看,附文章链接:

  1. Jest | 测试框架实践之-基础知识和环境搭建
  2. Jest | 测试框架实战之-测试用例编写与覆盖率解读

当我们执行jest --coverage,它会生成如下的测试报告:

jest-coverage.png 它是这么实现的呢?

原理猜测

通过生成的指标看出jest框架生成的覆盖率对语句、函数、分支、行数这4个维度进行了生成,如果对js编译原理有所了解,根据敏锐度大体能过猜测到应该是需要对jsast树解析,因为这几个指标的类型,在对应的ast数的节点类型上都有对应的体现。当解析成ast树,应该的存在某种机制能往树里面侵入部分统计代码,那么在执行的时候遍可以统计ast树哪些类型的节点是已经被执行了。

原理验证

了解库的实现原理,通常第一步是打开类库的package.json文件,看看它都依赖了什么。通过对该文件的排查,我们排除到这三个库:

jest-pkg.png

  1. istanbul-lib-coverage:提供覆盖率信息的只读视图,能够合并和汇总覆盖率信息的api
  2. istanbul-lib-report:istanbul库生成报告的核心程序
  3. istanbul-reports:大体提供报告输出的公共能力api

这三个库使用围绕着istanbul,因此该库基本大概率提供了核心的覆盖率能力,下面去验证下。

istanbul库

istanbul,为ES5和ES2015+JavaScript代码插入行计数器,这样您就可以跟踪单元测试对代码库的运行情况。

下面我们安装个看看:

npm install -g istanbul
复制代码

安装完成后,执行下istanbul help查看下它所支持的命名,所有核心命令如下:

  1. check-coverage:根据JSON文件的覆盖率阈值检查总体/每个文件的覆盖率。如果不满足阈值,则退出1,否则退出0。
  2. cover:透明地将覆盖率信息添加到节点命令。在执行结束时保存coverage.json和报告。
  3. instrument:插入文件或目录树,并将插入指令的代码写入所需的输出位置。
  4. report:为上一次运行中生成的JSON对象写入覆盖率报告。
instrument命令

改指令会插入代码,通常查找资料,它有个名称为叫:函数插桩,会给函数添加些代码。下面验证下:

// test.js文件
const toSum = (a, b) => {
  if (a > 10) {
    return a + b + 10;
  }
  return a;
};
toSum();
复制代码

test.js文件执行该命令添加代码,并输出到test-inst.js文件:

istanbul instrument ./test.js -o ./test-inst.js
复制代码

转换后的代码,通过格式化后如下:

jest-inst.png 可以看出如下信息:

  1. 它创建了一个全局对象用于存储统计信息
// 形式如下:
var coverages = {
  '/root/test.js':{
     path: '/root/test.js',
     // statement数量
     s: {},
     // branch数量
     b: {},
     // function数量
     f: {},
     // 记录function的开始结束位置
     fnMap: {},
     // 记录statement的开始结束位置
     statementMap: {},
     // 记录statement的开始结束位置
     branchMap: {}
  }
}
复制代码
  1. 它往函数执行代码各个对应位置插入了统计代码,对应代码块执行就+1
  2. 命名及其复杂防止与全局命名冲突。

这便是整个istanbul的流程,也是生成覆盖率的基本原理。

总结

这篇大体说明了jest测试覆盖率的生成原理,它的基本实现机制我们是能够了解的。至于istanbul库是如何实现函数函数插桩机制,它的原理,有空再说。

猜你喜欢

转载自juejin.im/post/7035139783911276551