使用 Jest 测试 Vue 应用

使用 Jest 测试 Vue 应用

Flying
2017-12-08 / 0 评论 / 147 阅读 / 正在检测是否收录...

要保证前端的代码质量,单元测试是少不了的。特别是对核心业务的代码,要更详细地进行单元测试。之前使用 Karma 写过 AngluarJS 单元测试。现在 vue 项目越来越多,怎么写 vue 的单元测试呢?记得 Vue CLI 的 webpack 模板是支持单元测试的。下面我们就来简单介绍一下怎样使用使用 Vue CLI 中的 Jes 运行器写单元测试。

jest-vue.svg

一、目录结构

准备 Vue CLI 项目。可以看到单元测试代码代码集中在 test/unit 文件夹中,其中 jest.conf.js 是 jest 的配置文件,请到 Jest 官网了解更多。setup.js 用来设置每个测试文件都引用的代码。.eslintrc 用来覆盖添加整个项目的 eslint 设置。

官方推荐单元测试写在 test/unit/specs 下,这样便于集中管理,Jest 测试运行器扫描也比较快。测试文件推荐以 .spec.js 结尾。项目中已经有 HelloWorld.spec.js 实例,是用来测试 HelloWorld 组件的。

HelloWorld.spec.js 就一个用例,测试 h1 标签的内容是否正确。Jest 写单元测试代码很简单,和 Jasmine 的 BDD 风格差不多。describe 创建测试套件,it 放置测试用例,expect 放置断言语句。想了解更多,可参考我以前写 Jasmine 简介

二、运行测试

npm run unit运行一下,居然报错:

SecurityError: localStorage is not available for opaque origins。

Google 了一下,原来 Vue CLI 项目中,Jest 默认的 testEnvironmentojsdomjsdom 升级导致不能向下兼容。具体可以查看 jsdom issues。解决方案解决方法就是更改 jest.config.js 里面的 testEnvironment 的字段为 node 就行了。

再次运行,控制台看到下面的输出就说明测试通过了。

module.exports = {
  ...
  testEnvironment: 'node'
};

三、编写测试

不容易呀,npm 再强大,包太多也管理不过来,这样的版本升级导致的 Bug 在前端的日常工作不小呀,幸好有万能的 Google。下面我们自己动手就来编写一个组件的单元测试。毕竟“纸上得来终觉浅”,得勤动手。

以下是一个简单的单文件组件:

<template>
  <div>
    <span class="count">{{ count }}</span>
    <button @click="increment">Increment</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>
<script>

export default {
  name: 'Counter',
  data () {
    return {
      count: 1
    }
  },
  methods: {
    increment () {
      this.count++
    },
    decrement () {
      this.count--
    }
  }
}
</script>

接下来我们来编写它的单元测试 Counter.spec.js

import Vue from 'vue'
import Counter from '@/components/Counter'

describe('Counter.vue', () => {
  const Constructor = Vue.extend(Counter)
  const vm = new Constructor().$mount()
  it('should render the correct tag', () => {
    const Constructor = Vue.extend(Counter)
    const vm = new Constructor().$mount()
    expect(vm.$el.innerHTML).toContain('<span class="count">1</span>')
  })

  it('should have 2 buttons', () => {
    expect(vm.$el.querySelectorAll('button')).toHaveLength(2)
  })

  it('count default value should one', () => {
    expect(vm.count).toBe(1)
  })
})

可以看到,我们引入了 Vue 和 Counter 组件,然后通过 extend 创建一个包含被挂载和渲染的 Vue 组件的实例,所有测试用例都是基于该实例来创建的。因此,我们将这部分代码放到用例代码块外共享。前面三个用例比较简单,基本上都是 Dom 元素或内容断言。

计数器的增减应该是测试的重点。不应该直接访问 Vue 组件的实例的方法来实现的,这种方式是反测试原则的,因为单元测试代码和组件代码耦合了。组件代码重构了,测试代码也要重写。我们应该通过点击按钮触发 click 事件来测试计数。但一时又找不到相关的 API。百度好几篇文章几乎都是说不支持。后来 Google 了一下,在 Github 上找到了一个大佬在一次 conf 的演讲上用的示例代码。他是用原生代码派发自定义事件来实现的。虽然这个方案不够优雅,但还是能解决问题的,添加如下两个测试用例:

it('should increment the count', () => {
    const button = vm.$el.querySelectorAll('button')[0]
    const customEvent = new Event('click')
    button.dispatchEvent(customEvent)
    expect(vm.count).toBe(2)
  })

  it('should decrement the count', () => {
    const button = vm.$el.querySelectorAll('button')[1]
    const customEvent = new Event('click')
    button.dispatchEvent(customEvent)
    expect(vm.count).toBe(1)
  })

注意:Vue CLI 单元测试是主要是通过 jestbabel-jestvue-jest 这些包完成的,知道了这一 点,我们也可以手动这已有的 vue 项目搭建搭建单元测试环境。

Vue 项目是先写测试瑞写代码?我认为在做鬼新项目而且时间足够的情况下使用 TDD 是最好的。但有的项目我们不得不赽进度或是中途参与进来的,先写代码再写测试也是可以理解的。

✌️Happy Test!

7

评论 (0)

取消