如何为vue的项目添加单元测试


Posted in Javascript onDecember 19, 2018

动机

  • 单元测试能避免出现一些代码运行结果与预期不符的错误,通常是一些比较低级但又难以发现的问题。
  • 粗心且懒,在每次调整之后,需要不断地检查代码,反复去走流程。担心由于自己的改动而导致了逻辑上的错误。而这里面的一大部分工作其实可以让单元测试来完成。
  • 有了单元测试之后,可以对代码本身形成一种规范。如果在进行单元测试过程中发现自己的一些代码不方便进行测试,那么你可能需要重新审视这些代码,看是否有一些设计上不合理或者可以优化的地方。
  • 嵌入了单元测试的项目显得更加的专业,也会更有逼格,测试本身是开发环节需要做的内容。

工具选取对比(一个合适测试框架 -- Jest)

之前也没有去接触过前端的单元测试,也是这几天开始了解,开始并没有头绪,所以就在网上以及github上去看了一些之前比较流行的测试框架。发现比较流行的是karma + mocha + Chrome的组合。当我单独一个个去看的时候,发现其内容还是比较的多的。之后选取了jest也是经过对比权衡的

优点

1、一站式的解决方案,学习成本更低,上手更快(很适合现如今我的需求)

在使用 Jest 之前,我需要一个测试框架(mocha),需要一个测试运行器(karma),需要一个断言库(chai),需要一个用来做 spies/stubs/mocks 的工具(sinon 以及 sinon-chai 插件),一个用于测试的浏览器环境(可以是 Chrome 浏览器,也可以用 PhantomJS)。 而使用 Jest 后,只要安装它,全都搞定了。

2、全面的官方文档,易于学习和使用

Jest 的官方文档很完善,对着文档很快就能上手。而在之前,我需要学习好几个插件的用法,至少得知道 mocha 用处和原理吧 我得学会 karma 的配置和命令,chai 的各种断言方法……,经常得周旋于不同的文档站之间,其实是件很烦也很低效的事

3、更直观明确的测试信息提示

4、方便的命令行工具

缺点

jsdom 的一些局限性:因为 Jest 是基于 jsdom 的,jsdom 毕竟不是真实的浏览器环境,它在测试过程中其实并不真正的“渲染”组件。这会导致一些问题,例如,如果组件代码中有一些根据实际渲染后的属性值进行计算(比如元素的 clientWidth)就可能出问题,因为 jsdom 中这些参数通常默认是 0.

综上所述,最终我确定下来的方案是使用成熟好用的测试工具库 --- vue-test-utils 其前身是 avoriaz,avoriaz 也是一个不错的包,但其 README 中有说明,当 vue-test-utils 正式发布的时候, 它将会被废弃。 vue-test-utils 能极大地简化 Vue.js 单元测试。 例如:Vue 单元测试,一般是像下面这样的(包括 vue-cli 提供的模板里默认也是这样):

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

describe('HelloWorld.vue', () => {
 it('should render correct contents', () => {
  const Constructor = Vue.extend(HelloWorld)
  const vm = new Constructor().$mount()
  expect(vm.$el.querySelector('.hello h1').textContent)
   .toEqual('Welcome to Your Vue.js App')
 })
})

使用 vue-test-utils 后,你可以像下面这样

import { shallow } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld'

describe('HelloWorld.vue', () => {
 it('should render correct contents', () => {
  const wrapper = shallow(HelloWorld, {
   attachToDocument: ture
  })

  expect(wrapper.find('.hello h1').text()).to.equal('Welcome to Your Vue.js App')
 })
})

可以看到代码更加简洁了。wrapper 内含许多有用的方法,上面的例子中所使用的 find() 其中最简单不过的一个。vue-test-utils 还有 createLocalVue() 等方法以及 stub 之类的功能,基本上可以完成绝大部分情况下的测试用例,这也是非常的实用的了。

安装使用

安装使用的方式很简单,由于想引入到现有的项目中来,现有的项目大多是vue-cli创建的,所以一开始的时候基本上是已经安装并配置好了 webpack、vue-loader 和 Babel。如果是比较原始的项目,也是可以单独安装的。

我们要做的第一件事就是安装 Jest 和 Vue Test Utils:

$ npm install --save-dev jest @vue/test-utils

然后我们需要在 package.json 中定义一个单元测试的脚本。

// package.json
{
 "scripts": {
  "test": "jest"
 }
}

在 Jest 中处理单文件组件

npm install --save-dev vue-jest

接下来在 package.json 中创建一个 jest 块:

{
 // ...
 "jest": {
  "moduleFileExtensions": [
   "js",
   "json",
   // 告诉 Jest 处理 `*.vue` 文件
   "vue"
  ],
  "transform": {
   // 用 `vue-jest` 处理 `*.vue` 文件
   ".*\\.(vue)$": "vue-jest"
  }
 }
}

具体的使用步骤

此处我根据自己的需求来进行整理

对页面内容的测试

// viewTest.vue
<template>
 <div class="hello">
  <h1>{{ msg }}</h1>
  <p>1212121</p>
 </div>
</template>

<script>
export default {
 name: 'viewTest',
 data () {
  return {
   msg: 'Welcome to Your Vue.js App'
  }
 }
}
// viewTest.spec
import { mount } from '@vue/test-utils'
import Component from '../../../src/components/viewTest'

describe('页面展示测试', () => {
 test('检查元素是否存在', () => {
  const wrapper = mount(Component)
  expect(wrapper.contains('.hello h1')).toBe(true)
  console.log(wrapper.find('.hello h1').text())
  expect(wrapper.text()).toContain('Welcome')
 })
})

这个是最简单的对页面的dom节点的测试,以及可以对文案进行一些测试,这些是比较基础的

对事件处理的测试

// event.vue
<template>
   <div>
    <h1>My To Do event</h1>
    <h2>wawawawawawa</h2>
    <input v-model="newItem">
    <button @click="addItemToList">Add</button>
    </br>
    <!--displays event -->
    <ul>
     <li v-for="item in listItems">{{ item }}</li>
    </ul>
   </div>
  </template>

  <script>
  export default {
   name: 'event',
   data () {
    return {
     listItems: ['buy food', 'play games', 'sleep'],
     newItem: ''
    }
   },
   methods: {
    addItemToList() {
     this.listItems.push(this.newItem);
     this.newItem = '';
    }
   }
  }
  </script>
// event.spec.js
// 从测试实用工具集中导入 `mount()` 方法
// 同时导入你要测试的组件
import { mount } from '@vue/test-utils'
import Component from '../../../src/components/itemEvent'

describe('事件触发测试', () => {
 test('事件触发测试', () => {
 // 现在挂载组件,你便得到了这个包裹器
  const wrapper = mount(Component)
  const button = wrapper.find('button')
  wrapper.setData({
   newItem: '添加测试项',
  })
  button.trigger('click')
  console.log(wrapper.text())
  expect(wrapper.text()).toContain('添加测试项')
 })
})

这里是在模拟用户交互的一个测试,当用户点击按钮的时候会把数据插入到当前的列表中来,所以最开始需要定位到这个按钮,可以用find(),之后要去触发这个事件, button.trigger('click'),然后把预期的结果,与按照流程的结果相比较,以达到测试的效果。这里模拟的是一个点击事件,当然,api也支持各种的鼠标事件以及键盘事件。

测试异步行为 平时的业务场景中肯定是离不开异步操作的,当发送一个接口请求的时候应该怎么去才做。Jest 运行测试用例同时可以模拟了 HTTP 库 axios,对预期结果可以进行设定和比较,比如:

// axios.js
export default {
 get: () => Promise.resolve({ data: 'response' })
}
<template>
 <div>
  <button @click="fetchResults">发送请求</button>
  {{value}}
 </div>

</template>

<script>
import axios from '../axios.js'

export default {
 data () {
  return {
   value: '初始值'
  }
 },
 methods: {
  async fetchResults () {
   const response = await axios.get('mock/service')
   this.value = response.data
   console.log(this.value)
  }
 }, 
 created (){
  console.log(axios.get)
 }
}
</script>
// async.spec.js
import { shallowMount } from '@vue/test-utils'
import async from '../../../src/components/async'
jest.mock('axios')

it('当点击按钮发送请求时检验返回值', () => {
 const wrapper = shallowMount(async)
 console.log(jest)
 wrapper.find('button').trigger('click')
 // expect(wrapper.value)
 expect(wrapper.vm.value).toBe('response')
 // console.log(wrapper.vm.value).toBe('初始值')
})

这个时候运行的话会报错误

如何为vue的项目添加单元测试

因为断言在 fetchResults 中的 Promise 完成之前就被调用了,所以value的值还是最开始的初始值。大多数单元测试库都提供一个回调来使得运行期知道测试用例的完成时机。Jest 和 Mocha 都是用了 done。我们可以和 $nextTick 或 setTimeout 结合使用 done 来确保任何 Promise 都会在断言之前完成。

  • 测试 Vue Router 使用

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
extjs 学习笔记 四 带分页的grid
Oct 20 Javascript
jquery.validate使用攻略 第五步 正则验证
Jul 01 Javascript
javascript 使td内容不换行不撑开
Nov 29 Javascript
js 表单提交后按钮变灰的实例代码
Aug 16 Javascript
js中单引号与双引号冲突问题解决方法
Oct 04 Javascript
解决jquery实现的radio重新选中的问题
Jul 03 Javascript
jQuery实现点击某个div打开层,点击其他div关闭层实例分析(阻止冒泡)
Nov 18 Javascript
原生JS实现 MUI导航栏透明渐变效果
Nov 07 Javascript
微信小程序实现图片上传功能实例(前端+PHP后端)
Jan 10 Javascript
使用 JavaScript 创建并下载文件(模拟点击)
Oct 25 Javascript
vue proxy 的优势与使用场景实现
Jun 15 Javascript
jQuery实现异步上传一个或多个文件
Aug 17 jQuery
浅谈Angular7 项目开发总结
Dec 19 #Javascript
mockjs+vue页面直接展示数据的方法
Dec 19 #Javascript
vue项目搭建以及全家桶的使用详细教程(小结)
Dec 19 #Javascript
vue使用Google地图的实现示例代码
Dec 19 #Javascript
JS实现获取自定义属性data值的方法示例
Dec 19 #Javascript
vue动态绑定class选中当前列表变色的方法示例
Dec 19 #Javascript
js指定日期增加指定月份的实现方法
Dec 19 #Javascript
You might like
一条久听不愿放下的DIY森海MX500,三言两语话神奇
2021/03/02 无线电
10款实用的PHP开源工具
2015/10/23 PHP
mac下多个php版本快速切换的方法
2016/10/09 PHP
PHP版微信第三方实现一键登录及获取用户信息的方法
2016/10/14 PHP
使用PHP连接多种数据库的实现代码(mysql,access,sqlserver,Oracle)
2016/12/21 PHP
YII2框架中使用yii.js实现的post请求
2017/04/09 PHP
微信公众平台开发教程②微信端分享功能图文详解
2019/04/10 PHP
数理公式,也可以这么唯美
2021/03/10 无线电
JS(JQuery)操作Array的相关方法介绍
2014/02/11 Javascript
jquery获得同源iframe内body下标签的值的方法
2014/09/25 Javascript
nodeJS代码实现计算交社保是否合适
2015/03/09 NodeJs
js实现按钮颜色渐变动画效果
2015/08/20 Javascript
jQuery validate 验证radio实例
2017/03/01 Javascript
详解Node.js 命令行程序开发教程
2017/06/07 Javascript
JS求Number类型数组中最大元素方法
2018/04/08 Javascript
详解Vue底部导航栏组件
2019/05/02 Javascript
使用React代码动态生成栅格布局的方法
2020/05/24 Javascript
Vue Router中应用中间件的方法
2020/08/06 Javascript
[01:21]DOTA2新纪元-7.0新版本即将开启!
2016/12/11 DOTA
[02:27]2018DOTA2亚洲邀请赛趣味视频之钓鱼大赛 谁是垂钓冠军?
2018/04/05 DOTA
跟老齐学Python之变量和参数
2014/10/10 Python
Django中实现点击图片链接强制直接下载的方法
2015/05/14 Python
python的Tqdm模块的使用
2018/01/10 Python
对Python 文件夹遍历和文件查找的实例讲解
2018/04/26 Python
python 移除字符串尾部的数字方法
2018/07/17 Python
python lambda表达式在sort函数中的使用详解
2019/08/28 Python
Python安装及Pycharm安装使用教程图解
2019/09/20 Python
python Opencv计算图像相似度过程解析
2019/12/03 Python
Java Unsafe类实现原理及测试代码
2020/09/15 Python
如何利用pycharm进行代码更新比较
2020/11/04 Python
python中的unittest框架实例详解
2021/02/05 Python
css3实现一款模仿iphone样式的注册表单
2013/03/20 HTML / CSS
C#里面如何判断一个Object是否是某种类型(如Boolean)?
2016/02/10 面试题
送货司机岗位职责
2013/12/11 职场文书
2014年社会实践活动总结范文
2014/04/29 职场文书
Python 实现绘制子图及子图刻度的变换等问题
2021/05/31 Python