简介

istanbul 是一个 JavaScript 代码覆盖率工具,它可以帮助我们分析代码的测试覆盖率,从而帮助我们更好的编写测试用例。在这篇文章中,我们将通过阅读 istanbul 的源码来了解它是如何实现代码覆盖率的。

项目结构

  • lib: 核心代码
  • misc: 一些工具
  • test: 测试用例
  • .jshintignore:指定哪些文件和目录应该被 JSHint 忽略,JSHint 是一个 JavaScript 代码质量工具。
  • .jshintrc:JSHint 的配置文件,定义代码质量检查的规则。
  • .travis.yml:Travis CI 的配置文件,用于持续集成服务的设置。
  • CHANGELOG.md:项目的变更日志,记录每个版本的更新内容。
  • coverage.json.md:代码覆盖率报告的 JSON 文件的解释
  • download-escodegen-browser.sh:一个 Shell 脚本,用于下载 escodegen 浏览器版本。
  • generate-pages.sh:一个 Shell 脚本,可能用于生成项目的文档页面。
  • ignoring-code-for-coverage.md:解释如何在代码覆盖率报告中忽略某些代码的文档。
  • yui-coverage-comparison.md:关于 YUI(Yahoo User Interface)库的代码覆盖率比较的文档。
  • yuidoc.json:YUIDoc 的配置文件,用于生成项目的文档。

核心代码

index.js

  • 导出核心模块,包括
    • Instrumenter
    • Store
    • Collector
    • hook
    • Report
    • config
    • Reporter
    • utils
    • VERSION
    • Writer
    • ContentWriter
    • FileWriter
    • _yuiLoadHook
    • TreeSummarizer
    • assetsDir

Instrumenter.js

  • 首先对node.js环境和浏览器环境进行判断,同时针对新老版本作出不同的处理

  • 定义语法对象 SYNTAX

  • 定义AST节点生成器 astgen

  • 定义AST节点遍历器 Walker,直接定义的构造函数。主要原型方法如下:

      1. startWalk(node) 从节点node开始游走遍历
      1. apply(node, walkFn, pathElement) 对节点node应用walkFn函数(遍历时的回调函数),pathElement是一个对象,用于记录当前节点的路径信息
  • 定义defaultWalker,walkFn的默认实现

  • 定义Instrumenter类,包括配置选项和Walker类配置

  • 定义Instrumenter原型方法,这些原型方法会在Waler类配置中设为回调函数,对AST节点进行遍历,插入代码

  • **插桩原理:**通过esprima生成JS代码的AST,随后通过escodegen在AST转化为代码时重新生成代码,构造覆盖率统计的全局变量,插入计数器代码,从而实现代码覆盖率的统计