要保证前端的代码质量,单元测试是少不了的。特别是对核心业务的代码,要更详细地进行单元测试。之前使用 Karma 写过 AngluarJS 单元测试。现在 vue 项目越来越多,怎么写 vue 的单元测试呢?记得 Vue CLI 的 webpack 模板是支持单元测试的。下面我们就来简单介绍一下怎样使用使用 Vue CLI 中的 Jes 运行器写单元测试。
一、目录结构
准备 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 默认的 testEnvironmento
为 jsdom
。jsdom
升级导致不能向下兼容。具体可以查看 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 单元测试是主要是通过jest
、babel-jest
、vue-jest
这些包完成的,知道了这一 点,我们也可以手动这已有的 vue 项目搭建搭建单元测试环境。
Vue 项目是先写测试瑞写代码?我认为在做鬼新项目而且时间足够的情况下使用 TDD 是最好的。但有的项目我们不得不赽进度或是中途参与进来的,先写代码再写测试也是可以理解的。
✌️Happy Test!
评论 (0)