专栏首页云前端[译] Vue 应用的代码覆盖率

[译] Vue 应用的代码覆盖率

  • 原文地址:https://vuejsdevelopers.com/2020/07/20/code-coverage-vue-cypress/
  • 原文作者:Gleb Bahmutov
  • 译文出自:"掘金翻译计划"(https://github.com/xitu/gold-miner)
  • 本文永久链接:https://github.com/xitu/gold-miner/blob/master/article/2020/code-coverage-vue-cypress.md

让我们像 ?bahmutov/vue-calculator 应用一样,借助 ?Vue CLI 来搭建一个 Vue 应用脚手架。在本文中,我将展示如何测量应用的源代码以收集其代码覆盖率信息。其后我们将利用该代码覆盖率报告来引导端到端测试的编写。

应用

示例应用可在 ?bahmutov/vue-calculator 找到,该仓库 fork 自脚手架阶段使用了 Vue CLI 默认模版的 ?kylbutlr/vue-calculator 项目。其代码使用如下 babel.config.js 文件转译:

// babel.config.js
module.exports = {
  presets: [
    '@vue/app'
  ]
}

当我们用 npm run serve 启动应用时,其实是执行了这条 NPM script

{
  "scripts": {
    "serve": "vue-cli-service serve"
  }
}

应用默认运行在 8080 端口上。

Vue 计算器应用

搞定!你可以计算任何想要的东西了。

测量源代码

我们可以通过向 Babel 配置文件导出对象中添加 plugins 列表来测量应用代码。该插件列表应包含 ?babel-plugin-istanbul 。

// babel.config.js
module.exports = {
  presets: [
    '@vue/app'
  ],
  plugins: [
    'babel-plugin-istanbul'
  ]
}

现在,当应用运行时,我们应该能找到 window.__coverage__ 对象,该对象包含了每条语句、每个函数,及每个文件的每一个分支的各种计数。

应用覆盖率对象

不过上面展示的覆盖率对象,仅包含了单一条目 src/main.js,却缺失了 src/App.vuesrc/components/Calculator.vue 两个文件。

让我们来告诉 babel-plugin-istanbul 我们想要同时测量 .js.vue 文件吧。

// babel.config.js
module.exports = {
  presets: [
    '@vue/app'
  ],
  plugins: [
    ['babel-plugin-istanbul', {
      extension: ['.js', '.vue']
    }]
  ]
}

提示: 我们可以将 istanbul 设置放在一个单独的 .nycrc 文件中(译注:?nyc ,Istanbul 提供的命令行接口工具),或将它们添加到 package.json。目前而言,还是先将这些设置一起保留在插件列表本身中吧。

当我们重启应用后,得到了一个包含 .js.vue 文件条目的新 window.__coverage__ 对象。

被测量的 JS 和 Vue 文件

条件性测量

如果你观察应用的打包结果,就会看到测量所做的事情。其围绕每条语句都插入了计数器,用以保持跟踪一条语句被执行了多少次。对于每一个函数和每一个分支路径,也有单独的计数器。

被测量的源代码

我们并不想测量生产环境代码。应仅在 NODE_ENV=test 时测量代码,好利用收集到的代码覆盖率帮助我们编写更好的测试。

// babel.config.js
const plugins = []
if (process.env.NODE_ENV === 'test') {
  plugins.push([
    "babel-plugin-istanbul", {
      // 在此为 NYC 测量工具指定一些选项
      // 如告知其同时测量 JavaScript 和 Vue 文件
      extension: ['.js', '.vue'],
    }
  ])
}
module.exports = {
  presets: [
    '@vue/app'
  ],
  plugins
}

可以通过设置环境变量启动带测量的应用。

$ NODE_ENV=test npm run serve

提示: 对于跨平台可移植性,可使用 ?cross-env 工具设置一个环境变量。

端到端测试

现在我们测量了源代码,使用其引导编写测试吧。我将用官方的 Vue CLI 插件 ?@vue/cli-plugin-e2e-cypress 安装 Cypress Test Runner。而后我将安装 ?Cypress 代码覆盖率插件 以在测试运行结束时将覆盖率对象转换为人和机器皆可读的报告。

$ vue add e2e-cypress
$ npm i -D @cypress/code-coverage
+ @cypress/code-coverage@3.8.1

?@vue/cli-plugin-e2e-cypress 已经创建了 tests/e2e 文件夹,在其 support 和 plugins 子目录的文件中都可以加载代码覆盖率插件。

// 文件 tests/e2e/support/index.js
import '@cypress/code-coverage/support'

// 文件 tests/e2e/plugins/index.js
module.exports = (on, config) => {
  require('@cypress/code-coverage/task')(on, config)
  // 重要:须返回包含任何改变过的环境变量的配置对象
  return config
}

让我们为被 ?@vue/cli-plugin-e2e-cypress 插入到 package.json 中的 NPM script 命令 test:e2e 设置环境变量 NODE_ENV=test

{
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:e2e": "NODE_ENV=test vue-cli-service test:e2e"
  }
}

可将我们的首个端到端规格文件置于 tests/e2e/integration 文件夹:

/// <reference types="cypress" />
describe('Calculator', () => {
  beforeEach(() => {
    cy.visit('/')
  })
  it('computes', () => {
    cy.contains('.button', 2).click()
    cy.contains('.button', 3).click()
    cy.contains('.operator', '+').click()
    cy.contains('.button', 1).click()
    cy.contains('.button', 9).click()
    cy.contains('.operator', '=').click()
    cy.contains('.display', 42)
    cy.log('**division**')
    cy.contains('.operator', '÷').click()
    cy.contains('.button', 2).click()
    cy.contains('.operator', '=').click()
    cy.contains('.display', 21)
  })
})

本地运行时,我将使用 npm run test:e2e 命令启动应用并打开 Cypress 。以上测试很快通过了。我们的计算器看起来加法除法运行良好。

计算器测试

正如你能从来自于 Test Runner 命令行日志信息的左侧看到的,测试覆盖率插件在运行结束时自动生成了代码覆盖率报告。报告被存储在 coverage 文件夹中,且默认有多种输出格式。

coverage/
  lcov-report/
    index.html         # 人类可读的 HTML 报告
    ...
  clover.xml           # 面向 Clover Jenkins reporter 的覆盖率报告
  coverage-final.json  # 纯 JSON 输出
  lcov.info            # 面向第三方报告服务的行覆盖率

在本地运行测试时,我更喜欢打开 HTML 覆盖率报告:

$ open coverage/lcov-report/index.html

index.html 是一个展示了每个源代码文件夹覆盖率信息表格的静态页面。

覆盖率报告

提示: 将整个 coverage/lcov-report 文件夹作为一个测试产物存储在你的持续集成(CI - Continuous Integration)服务器上。然后就能在测试运行后浏览或下载报告以查看收集到的代码覆盖率了。

端到端测试是 有效的。通过一个加载整个应用并与之交互的单一测试,我们覆盖了近 60% 的源代码。更棒的是,通过点开单独的文件,我们发现了在 src/components/Calculator.vue 中那些未曾被测试到的特性。

Calculator.vue 中已覆盖/未覆盖的行

源码中高亮为红色的行正是测试中遗漏的。可以看到,虽然我们已经测试了录入数字和除法等,但仍需编写一个测试以覆盖“清理当前数字”、“改变正负号”、“设置小数点”、“乘法”等功能。代码覆盖率因此变为了编写端到端测试的向导;增加测试,直到所有红色标记的行都被干掉为止!

  Calculator
    ✓ computes adds and divides (1031ms)
    ✓ multiplies, resets and subtracts (755ms)
    ✓ changes sign (323ms)
    ✓ % operator (246ms)

随着编写更多的测试,我们在应用中快速收获了覆盖率和信心。在最后一项测试中我们将覆盖仍保留了红色的 decimal () { ... } 方法。

没有被覆盖到的 Decimal 方法

以下测试键入了一个单数位数字并点击了 "." 按钮。显示结果应为 "5." 。

it('decimal', () => {
  cy.contains('.button', '5').click()
  cy.contains('.button', '.').click()
  cy.contains('.display', '5.')
})

嘿,怪了,测试失败了。

Decimal 测试失败

Cypress 测试的一个强大之处就在于其运行在真实浏览器中。让我们来调试失败的测试。在 src/components/Calculator.vue 放置一个端点。

decimal() {
  debugger
  if (this.display.indexOf(".") === -1) {
    this.append(".");
  }
},

打开浏览器的 DevTools 并再次运行测试。测试将运行,直到遇见应用代码中的 debugger 关键字。

调试 decimal 方法

噢,this.display 是个数字,而非一个字符串。因此 .indexOf() 并不存在且 this.display.indexOf(".") 表达式抛出了一个错误。

提示: 如果想要在任何一次 Vue 捕获错误时都让 Cypress 测试失败,在你的应用代码中做如下设置:

// 从代码覆盖率中排除这些行
/* istanbul ignore next */
if (window.Cypress) {
  // 将 Vue handler 捕获的任何错误发送给
  // Cypress 顶级错误处理器以使测试失败
  // https://github.com/cypress-io/cypress/issues/7910
  Vue.config.errorHandler = window.top.onerror
}

让我们来修复代码中的错误逻辑:

decimal() {
  if (String(this.display).indexOf(".") === -1) {
    this.append(".");
  }
},

测试通过了。现在代码覆盖率报告又告诉我们条件语句的 "Else" 路径并未被考虑到。

没有 Else 路径

扩展测试以在测试中两次点击 "." 操作符,这将覆盖所有代码路径并将整个方法覆盖率变为绿色。

it('decimal', () => {
  cy.contains('.button', '5').click()
  cy.contains('.button', '.').click()
  cy.contains('.display', '5.')
  cy.log('**不会加两次**')
  cy.contains('.button', '.').click()
  cy.contains('.display', '5.')
})

Decimal 测试通过

全覆盖的代码路径

现在再次运行所有测试。所有测试在 3 秒钟之内通过了。

所有测试都通过了

这些测试一起覆盖了我们整个的代码库。

完整的代码覆盖率

总结

  • 向已经使用了 Babel 转译源代码的 Vue 项目添加代码测量工具很简单。向插件列表中添加 babel-plugin-istanbul 就能在 window.__coverage__ 对象中获知代码覆盖率信息。
  • 为避免减慢生产环境运行的代码,你可能只想在运行测试时测量源代码。
  • 因为运行了完整的应用,端到端测试对于覆盖大量代码非常有效。
  • @cypress/code-coverage 插件产生的代码覆盖率报告可以引导你编写测试以确保所有特性都被测试到

本文分享自微信公众号 - 云前端(fewelife),作者:云前端

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 代码覆盖率 Istanbul的简单使用

    来看一个例子,怎么使用 Istanbul 。下面是脚本文件 simple.js 。

    javascript.shop
  • 100%代码覆盖率的悲剧

    张树臣
  • 100%代码覆盖率的悲剧

    本文Daniel Lebrero在大数据团队担任IG的技术架构师。拥有超过15年的Java经验和4年的Clojure经验,他现在是函数式编程的大力倡导者。 以下...

    CSDN技术头条
  • 100%代码覆盖率的悲剧

    本文Daniel Lebrero在大数据团队担任IG的技术架构师。拥有超过15年的Java经验和4年的Clojure经验,他现在是函数式编程的大力倡导者。 以下...

    华章科技
  • 真机的代码覆盖率测试

    代码覆盖率测试 以前虽然写过单元测试,但很少监测测试的完整程度,测试用例也经常存在重复的情况。这次在测试的要求下开始接入代码覆盖率测试。什么是代码覆盖率?就是测...

    落影
  • UnitTest:maven中使用Jacoco计算代码覆盖率

    jacoco 官网 https://www.eclemma.org/jacoco/

    测试邦
  • 使用gcov和lcov测试代码覆盖率

    通过gcov和lcov,可以很直观的看到代码的运行情况,同时也可以查看代码的行覆盖率,函数覆盖率等等信息,为开发提供一个方便的测试手段。

    编程珠玑
  • [Azure Devops] 获取单元测试的代码覆盖率

    上一篇文章里,我们在 Pipeline 中插入一个单元测试并把所有单元测试都通过作为 Pipeline 通过的硬性要求。除此以外,我们还可以获取单元测试的代码覆...

    dino.c
  • Jacoco统计接口测试的代码覆盖率

    搜狗商城现有的接口自动化测试框架是使用Python搭建的,共900多条case,每天都会运行一次,从而监控是否有因开发代码变更或者新功能添加而导致的遗漏...

    用户5521279
  • 使用dropwizard(4)-加入测试-jacoco代码覆盖率

    前言 dropwizard提供了一个简单的测试框架。这里简单集成并加入jacoco测试。 Demo source https://github.com/Rya...

    Ryan-Miao
  • 使用 Gcov 和 LCOV 度量 C/C++ 项目的代码覆盖率

    本篇分享如何使用 Gcov 和 LCOV 对 C/C++ 项目进行代码覆盖率的度量,以及在之前 关于代码覆盖率(Code Coverage) 篇中没有提到的观点...

    Peter Shen
  • 前端精准测试探索:覆盖率实时统计工具

    随着业务增长,随之而来的前端需求激增,如何在有限的时间内保证前端代码的质量。通过测试同学单方面的保障,还是免不了前端线上问题,存在回归不到位或者测试遗漏的地方,...

    有赞coder
  • C++语言的单元测试与代码覆盖率

    直接交付没有经过测试的代码是不太好的,因为这很可能会浪费整个团队的时间,在一些原本早期就可以发现的问题上。而单元测试,就是发现问题一个很重要的环节。

    小老鼠
  • 利用JaCoCo统计接口测试中代码覆盖率

    做接口测试,很多时候都会听到,你接口测试的覆盖率是多少?很多人会回答80%,你怎么统计的,他说覆盖了80%的需求。这个回答没有错误,但是片面,我...

    雷子
  • 使用JaCoCo Maven插件创建代码覆盖率报告

    这篇博客文章描述了我们如何使用JaCoCo Maven插件为单元和集成测试创建代码覆盖率报告。

    FunTester
  • 教你使用 Jacoco 统计服务端代码覆盖率

    前面有一篇 文章 使用 Python + Coverage 来统计测试用例的代码覆盖率

    AirPython
  • 从0到1,带你尝鲜Vue3.0

    做一个简单的Helloworld测试 我们就先试试原有的vue2 的Api还可不可以使用。

    前端达人
  • Code Coverage API plugin 一个新的代码覆盖率插件

    Code Coverage API plugin 是 Jenkins 在 GSoC 2018 中的一个子项目。GSoC 是一个由谷歌举办的,帮助在校学生进入开源...

    LinuxSuRen
  • 使用 coverlet 查看.NET Core应用的测试覆盖率

    代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率。

    solenovex

扫码关注云+社区

领取腾讯云代金券