专栏首页云前端[译] 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 插件产生的代码覆盖率报告可以引导你编写测试以确保所有特性都被测试到
文章分享自微信公众号:
云前端

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:云前端
原始发表时间:2020-09-08
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 100%代码覆盖率的悲剧

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

    华章科技
  • 100%代码覆盖率的悲剧

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

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

    CSDN技术头条
  • 真机的代码覆盖率测试

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

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

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

    javascript.shop
  • node的事件模块应用(译)

    第一次接触Node.js时,就觉得他只不过是用javascript实现的服务端。但实际上他提供了许多浏览器端不具备的方法,比如EventEmitter类。我们在...

    IMWeb前端团队
  • Jacoco统计接口测试的代码覆盖率

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

    用户5521279
  • [Azure Devops] 获取单元测试的代码覆盖率

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

    dino.c
  • 【译】使用箭头函数精简你的 Vue 模块

    最近在重构一个用 Vue1.0 写的项目,我通过使用 ES6 的箭头函数来让代码在不升级 Vue2.0 的情况下变得更加简洁和统一。在这个过程中我也遇到了很多坑...

    IMWeb前端团队
  • 【译】使用箭头函数精简你的 Vue 模块

    本文作者:IMWeb ShiJianwen 原文出处:IMWeb社区 未经同意,禁止转载 原文链接:https://dotdev.co/clean-...

    IMWeb前端团队
  • 使用 coverlet 查看.NET Core应用的测试覆盖率

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

    solenovex
  • 「译」代码整洁之道的 7 个方法

    在这篇短文中,我将介绍一些你可以用来改进你的代码的方法。本文代码示例均使用 JavaScript。

    HelloGitHub
  • Google 内部的 Python 代码风格指南(译)

    这是一位朋友翻译的Google Python代码风格指南,很全面。可以作为公司的code review 标准,也可以作为自己编写代码的风格指南。希望对你有帮助。...

    逆锋起笔
  • 【速来围观】IAR环境下代码覆盖率功能的使用

    在设计测试程序,验证是否所有的代码都被执行到时,就要考虑到代码覆盖率,IAR环境下的代码覆盖率是一个在这方面很有用的功能,且使用方便,今天我们就来讲讲这一功能如...

    用户1605515
  • (译)发现 Serverless 应用中的隐形成本

    像 AWS Lambda 这样的服务,代码每运行 100 毫秒,就需要支付一定的费用。例如 512 MB 内存的 Lambda 的(每 100 毫秒)费率是 $...

    崔秀龙
  • 【译】送给你的代码审查问题手册

    代码审查列表,是代码审查的明确规则和指导手册,它可以使代码审查为你的团队带来更多好处,并且能够显著提升代码审查的速度。

    Jackeyzhe
  • JaCoCo代码覆盖率从0到100的入门实践

    JaCoCo全称是Java Code Coverage,Java代码覆盖率,广泛运用于各种测试平台对Java代码的全量覆盖率和增量覆盖率进行统计,分析代码行差异...

    dongfanger
  • 干货 | 如何利用Xcode实现线上代码覆盖率的检查

    携程技术

扫码关注腾讯云开发者

领取腾讯云代金券