如何为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 相关文章推荐
响应鼠标变换表格背景或者颜色的代码
Mar 30 Javascript
使用javascript过滤html的字符串(注释标记法)
Jul 08 Javascript
js判断客户端是iOS还是Android等移动终端的方法
Dec 11 Javascript
Jquery图片延迟加载插件jquery.lazyload.js的使用方法
May 21 Javascript
js实现点击添加一个input节点
Dec 05 Javascript
js实现touch移动触屏滑动事件
Apr 17 Javascript
javaScript实现滚动新闻的方法
Jul 30 Javascript
浅析Javascript匿名函数与自执行函数
Feb 06 Javascript
AngularJS 与Bootstrap实现表格分页实例代码
Oct 14 Javascript
利用Vue.js实现checkbox的全选反选效果
Jan 18 Javascript
Vue单页及多页应用全局配置404页面实践记录
May 22 Javascript
JS数据类型STRING使用实例解析
Dec 18 Javascript
浅谈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
php实现简单的语法高亮函数实例分析
2015/04/27 PHP
在WordPress中获取数据库字段内容和添加主题设置菜单
2016/01/11 PHP
laravel 判断查询数据库返回值的例子
2019/10/11 PHP
JS拖动技术 关于setCapture使用
2010/12/09 Javascript
js中关于new Object时传参的一些细节分析
2011/03/13 Javascript
js动态给table添加/删除tr的方法
2013/08/02 Javascript
Microsfot .NET Framework4.0框架 安装失败的解决方法
2013/08/14 Javascript
AngularJs动态加载模块和依赖注入详解
2016/01/11 Javascript
javascript自动恢复文本框点击清除后的默认文本
2016/01/12 Javascript
NodeJs中express框架的send()方法简介
2017/06/20 NodeJs
JS实现评价的星星功能
2017/08/20 Javascript
AngularJS动态添加数据并删除的实例
2018/02/27 Javascript
基于rollup的组件库打包体积优化小结
2018/06/18 Javascript
angular1.x ui-route传参的三种写法小结
2018/08/31 Javascript
微信小程序实现多行文字超出部分省略号显示功能
2019/10/23 Javascript
node静态服务器实现静态读取文件或文件夹
2019/12/03 Javascript
webpack3.0升级4.0的方法步骤
2020/04/02 Javascript
通过python下载FTP上的文件夹的实现代码
2013/02/10 Python
Python smallseg分词用法实例分析
2015/05/28 Python
利用Python操作消息队列RabbitMQ的方法教程
2017/07/19 Python
python+selenium识别验证码并登录的示例代码
2017/12/21 Python
pyqt5自定义信号实例解析
2018/01/31 Python
解决Python requests库编码 socks5代理的问题
2018/05/07 Python
python微元法计算函数曲线长度的方法
2018/11/08 Python
python opencv 二值化 计算白色像素点的实例
2019/07/03 Python
pytorch自定义初始化权重的方法
2019/08/17 Python
pandas apply多线程实现代码
2020/08/17 Python
Python爬虫新手入门之初学lxml库
2020/12/20 Python
CSS3中几个新增加的盒模型属性使用教程
2016/03/01 HTML / CSS
湖南卫视在线视频媒体平台:芒果TV
2019/10/30 全球购物
中英文自我评价语句
2013/12/20 职场文书
人事部主管岗位职责
2013/12/26 职场文书
大学生考试作弊检讨书
2014/09/21 职场文书
《实心球》教学反思
2016/02/23 职场文书
2019大学竞选班长发言稿
2019/06/27 职场文书
浅谈Redis在直播场景的实践方案
2021/04/27 Redis