技术 二月 28, 2020

为 Cypress 的 e2e 测试增加代码覆盖率检测

文章字数 4.7k 阅读约需 4 mins. 阅读次数 1000000

之前写过一篇关于 如何使用 Cypress 进行端到端测试 的文章, 介绍了如何给 Vue 项目添加端到端测试。我们也体会到了 Cypress 做端到端测试的方便,作为 Vue 内置在官方脚手架中推荐的测试框架,不少项目已经引入并开始使用了。当你的项目已经添加了 Cypress 端到端测试,你的内心一定会很在意“我的测试到底充不充分?有没有浪费过多的经历在测试上?”这两个极端的问题。
引用官方的一段话

As you write more and more end-to-end tests, you will find yourself wondering - do I need to write more tests? Are there parts of the application still untested? Are there parts of the application that perhaps are tested too much? One answer to those questions is to find out which lines of the application’s source code were executed during end-to-end tests. If there are important sections of the application’s logic that were not executed from the tests, then a new test should be added to ensure that part of our application logic is tested.

我们可以通过添加代码覆盖率来从一定程度上减少我们这方面的顾虑。至少代码覆盖率能从一定程度上反映出测试的健康程度。前端代码测试覆盖率上的事实标准框架就是 Istanbul 了。本文就是结合了 Cypress 和 Istanbul 做到端到端的代码测试覆盖率的。官方也有一个教程 code coverage, 我也是参考了这篇教程,并且利用了官方提供的插件 -@cypress/code-coverage。但是从目前的时间点来看(2020 年 2 月 29 日),官方的教程并不能让你成功的在 vue-cli 创建出来的项目中做到代码覆盖率检查。那么下面就跟着我的顺序,来做吧。先奉上我 这篇文稿的 Demo

添加依赖库

前端代码覆盖率需要侵入修改我们的代码,在代码中插入一些探针来检查代码是否被执行。nyc是 Istanbul 的命令行工具,咱们也是利用这个工具来做到在代码中放置探针的工作的。但是命令行工具还是过于麻烦,我们需要先利用 nyc 修改我们的代码,然后以新的代码启动运行我们的项目,再做测试才可以收集到覆盖率情况。好在 Istanbul 提供了 babel 工具实时转换我们的代码。
所以我们需要安装依赖

npm i -D @cypress/code-coverage nyc istanbul-lib-coverage babel-plugin-istanbul@5.2.0

配置

配置 cypress 插件

在 Cypress 的 support 文件和 plugins 文件中分别添加下面的代码

// tests/e2e/support/index.js
import '@cypress/code-coverage/support'
// tests/e2e/plugins/index.js
module.exports = (on, config) => {on('task', require('@cypress/code-coverage/task'))
}

配置 nyc

在项目根目录添加.nycrc 文件

// .nycrc
{"extension": [".js", ".vue"], // 这里配置支持的文件类型
  "include": ["src/**/*.{js,vue}"],
  "all": true,
  "sourceMap": false,
  "instrument": false,
  "per-file": true
}

配置 babel

在 babel 配置文件中添加 babel-plugin-istanbul 插件

module.exports = {
  presets: ['@vue/cli-plugin-babel/preset']
}

// Only instrument code when running e2e tests
if (process.env.npm_lifecycle_script === 'vue-cli-service test:e2e') {console.log('Instrument the code')
  module.exports.plugins = [
    ['istanbul', {useInlineSourceMaps: false}]
  ]
}

这段就是只有在进行端到端测试的时候才往 babel 中添加这个插件,避免影响性能。

运行

这时候,所有的配置都完成了,相信注意看的同学都注意到了,我们安装了 babel-plugin-istanbul 的 5.2.0 版本,目前最新版是 6.0.0,为什么不安装最新版呢?答:因为有坑啊!而且目前网上所有地方都没有提到这个坑。也就是 6.0.0 版本与 5.2.0 版本有一个巨大的差异,也就是读取 nyc 配置文件的方式发生了变化,但是官方的 ChangeLog 里面都没有提到。

依赖对比图

此处的差异导致了 6.0.0 版本按照我们这种方法进行配置,并不能正常读取 nyc 的配置。我们配置了支持的扩展名称(vue 和 js),这个配置不能生效,导致代码覆盖率跑出来就只支持默认的 js 文件了。所以我们才引入了 5.2.0 版本。但是说不定 babel-plugin-istanbul 后续的版本可以解决这个问题,那时候就可以放心安装最新版了。

激动的时刻到了,接下来我们运行

npm run test:e2e

可以看到 e2e 测试正在运行,通过关键点可以看出代码覆盖率生效了

测试截图

测试跑完以后,代码覆盖率报告可以在 coverage 文件夹内看到了。

测试报告

与 CI 系统结合的话,我们通常需要一个纯 text 版本的覆盖率信息,利用 nyc 可以生成。
执行下面的命令

npx nyc report

npx nyc report --reporter=text-summary

CI 测试报告

0%