详解Vue单元测试case写法


Posted in Javascript onMay 24, 2018

书接上文,karma+webpack搭建vue单元测试环境介绍了vue单元测试环境搭建及查看源文件的测试覆盖覆盖率。今天来说一下vue单元测试思路和case的写法。测试框架使用jasmine,语法参考。

代码地址:https://github.com/MarxJiao/vue-karma-test/tree/spec-demo

测试关注点

对于vue组件,单元测试测试主要关注以下几点:

  1. vue组件加载后,各数据模型是否符合预期
  2. 定义的方法是否可用
  3. filter是否可用
  4. 带有props的组件,数据能否正常传递
  5. 异步更新DOM的情况

组件加载后的状态

要测试组件加载后的状态,首先我们需要将vue组件生成实例。并检测挂载后实例的数据状态。下面是个示例:

我们来看下src/app.vue组件的代码:

<template>
 <div>
  <h1>{{title}}</h1>
  <vc-message :message="message"></vc-message>
 </div>
</template>

<script>
 import child from './components/child.vue'
 export default {
  data() {
   return {
    title: '标题',
    message: '这是子组件'
   }
  },
  components: {
   'vc-message': child
  },
  mounted() {
   this.title = 'Hello world'
  },
  methods: {
   setMessage(msg) {
    this.message = msg;
   }
  }
 }
</script>

组件加载后title的值应该变成'Hello world',所以我们这样来写测试代码

// 引用vue
import Vue from 'vue';

// 引用要测试的组件
import app from '../../src/app.vue';

// 描述要测试的内容
describe('test app.vue', () => {
 
 // 描述要测试的最小单元
 it('组件加载后,title应该是Holle world', () => {

  // 这里将app生成vue实例,并使用 $mount() 模拟挂载状态
  let vm = new Vue(app).$mount();

  // 断言组件的title是否变为了'Hello world'
  expect(vm.title).toEqual('Hello world');
 });
});

执行karma start我们能看到测试通过。

测试组件里面的方法

我们知道vue将data和methods都挂在了vue实例的根节点下,所以测试vue组件中的方法也和上面测试状态一样,直接调用vm的方法就行了。我们来测试以下setMessage方法:

// 引用vue
import Vue from 'vue';

// 引用要测试的组件
import app from '../../src/app.vue';

// 描述要测试的内容
describe('test app.vue', () => {
 
 // 描述要测试的最小单元
 it('设置message为『你好世界』', () => {

  // 这里将app生成vue实例,并使用 $mount() 模拟挂载状态
  let vm = new Vue(app).$mount();

  // 执行setMessage方法
  vm.setMessage('你好世界');

  // 断言组件的message是否变为了'你好世界'
  expect(vm.message).toEqual('你好世界');
 });
});

执行karma start,就会看到测试成功。如果刚才没有关闭karma的话,在watch模式下,测试会自动进行。

怎么样?有没有感觉vue单元测试非常简单,赶紧做起来吧。

filter测试

filter的测试就更简单了。filter就是纯函数,有固定的输入输出,我们只需要执行函数看预期结果就好了。我们为组件添加一个转换大写的filter:

<template>
...

 <h1>{{title | upperCase}}</h1>

...

</template>

<script>

...

 filters: {
  upperCase(str) {
   return str.toUpperCase();
  }
 }

...
</script>

测试这个filter

// 引用要测试的组件
import app from '../../src/app.vue';

// 描述要测试的内容
describe('test app.vue', () => {

 it('upperCase过滤器能把app转换为APP', () => {

  // vue 组件export出来的是个对象,我们直接用这个对象的属性和方发就能调用到要测试的filter
  let appStr = app.filters.upperCase('app');

  // 断言组件的appStr是为'APP'
  expect(appStr).toEqual('APP');
 });
})

props测试

props依赖父组件,这个怎么测试呢。我们来看下vue官方提供的方法

使用Vue.extend()将组件挂载Vue构造器上,用propsData加入props数据,之后new一个Vue实例,这样就生成了一个独立的带props的vm和前面的实例一样,可以进行各种测试。

我们的child组件:

<template>
 <div>
  <div>{{message}}</div>
 </div>
</template>

<script>
 export default {
  props: ['message']
 }
</script>

测试child组件

// 引用vue
import Vue from 'vue';

// 引用要测试的组件
import child from '../../src/components/child.vue';

/**
 * 获取生成的vm
 *
 * @param {Object} Component 组件
 * @param {Object} propsData props数据
 * @return {Object} vue实例
 */
function getRenderedVm (Component, propsData) {
 const Ctor = Vue.extend(Component)
 const vm = new Ctor({ propsData }).$mount()
 return vm
}

// 描述要测试的内容
describe('test child.vue', () => {
 
 // 描述要测试的最小单元
 it('组件加载后,child组件的message应该是「这是子组件」', () => {
  let childvm = getRenderedVm(child, {
   message: '这是message'
  });

  // 断言组件的child组件的props是否生效
  expect(childvm.message).toEqual('这是message');
 });
});

是不是so easy.

异步更新DOM的情况

异步更新DOM的情况,参考vue官网的示例

使用Vue.nextTick来查看异步数据更新后dom是否变化

// 引用vue
import Vue from 'vue';

// 引用要测试的组件
import app from '../../src/app.vue';

// 描述要测试的内容
describe('test app.vue', () => {
 
 // 异步数据更新
 it('数据更新后,视图应该改变', done => {

  // 这里将app生成vue实例,并使用 $mount() 模拟挂载状态
  let vm = new Vue(app).$mount();

  // 挂载后改变title
  vm.title = 'APP';

  Vue.nextTick(() => {
   let title = vm.$el.getElementsByTagName('h1')[0]
   expect(title.textContent).toEqual('APP')
   done();
  })
 });
});

以上就是对vue组件单元测试的用例编写的介绍,例子举得比较简单,主要是介绍各种情况的测试方法。

相关链接

Vue官网单元测试介绍

Jasmine introduction

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

Javascript 相关文章推荐
Javascript 中的 call 和 apply使用介绍
Feb 22 Javascript
浅谈jQuery中 wrap() wrapAll() 与 wrapInner()的差异
Nov 12 Javascript
理解javascript回调函数
Dec 28 Javascript
jQuery实现鼠标单击网页文字后在文本框显示的方法
May 06 Javascript
js插件Jcrop自定义截取图片功能
Oct 14 Javascript
ES6学习笔记之正则表达式和字符串正则方法分析
Apr 25 Javascript
JavaScript实现树的遍历算法示例【广度优先与深度优先】
Oct 26 Javascript
JS实现登录页密码的显示和隐藏功能
Dec 06 Javascript
Vue 重置组件到初始状态的方法示例
Oct 10 Javascript
CryptoJS中AES实现前后端通用加解密技术
Dec 18 Javascript
layer.open组件获取弹出层页面变量、函数的实例
Sep 25 Javascript
JavaScript canvas基于数组生成柱状图代码实例
Mar 06 Javascript
微信小程序通过保存图片分享到朋友圈功能
May 24 #Javascript
karma+webpack搭建vue单元测试环境的方法示例
May 24 #Javascript
react实现点击选中的li高亮的示例代码
May 24 #Javascript
浅谈Webpack 是如何加载模块的
May 24 #Javascript
jquery.onoff实现简单的开关按钮功能(推荐)
May 24 #jQuery
详解javascript中的变量提升和函数提升
May 24 #Javascript
JavaScript轮播停留效果的实现思路
May 24 #Javascript
You might like
免费手机号码归属地API查询接口和PHP使用实例分享
2014/04/10 PHP
php 字符串中是否包含指定字符串的多种方法
2018/04/12 PHP
laravel 字段格式化 modle 字段类型转换方法
2019/09/30 PHP
filemanage功能中用到的common.js
2007/04/08 Javascript
模拟jQuery ajax服务器端与客户端通信的代码
2011/03/28 Javascript
详解强大的jQuery选择器之基本选择器、层次选择器
2012/02/07 Javascript
jquery解析xml字符串简单示例
2014/04/11 Javascript
JS简单限制textarea内输入字符数量的方法
2015/10/14 Javascript
深入学习jQuery Validate表单验证
2016/01/18 Javascript
深入理解JS中的substr和substring
2016/04/26 Javascript
JS组件Bootstrap实现弹出框效果代码
2016/04/26 Javascript
jquery自定义插件——window的实现【示例代码】
2016/05/06 Javascript
浅谈js中的in-for循环
2016/06/28 Javascript
Bootstrap中的Dropdown下拉菜单更改为悬停(hover)触发
2016/08/31 Javascript
JS实现图片放大缩小的方法
2017/02/15 Javascript
js 将input框中的输入自动转化成半角大写(税号输入框)
2017/02/16 Javascript
利用webstrom调试Vue.js单页面程序的方法教程
2017/06/06 Javascript
php register_shutdown_function函数详解
2017/07/23 Javascript
解决vue 更改计算属性后select选中值不更改的问题
2018/03/02 Javascript
vue2之简易的pc端短信验证码的问题及处理方法
2019/06/03 Javascript
Vue.js中的extend绑定节点并显示的方法
2019/06/20 Javascript
使用vue3重构拼图游戏的实现示例
2021/01/25 Vue.js
Python写的Discuz7.2版faq.php注入漏洞工具
2014/08/06 Python
python判断字符串编码的简单实现方法(使用chardet)
2016/07/01 Python
mysql 之通过配置文件链接数据库
2017/08/12 Python
在django中图片上传的格式校验及大小方法
2019/07/28 Python
python实现Pyecharts实现动态地图(Map、Geo)
2020/03/25 Python
Django 实现 Websocket 广播、点对点发送消息的代码
2020/06/03 Python
.NET方向面试题
2014/11/20 面试题
毕业生优秀推荐信
2013/11/26 职场文书
拆迁委托协议书
2014/09/15 职场文书
2019大学生暑期实习心得总结
2019/08/21 职场文书
导游词之苏州阳澄湖
2019/11/15 职场文书
解决mysql:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO/YES)
2021/06/26 MySQL
深入讲解Vue中父子组件通信与事件触发
2022/03/22 Vue.js
Navicat Premium自定义 sql 标签的创建方式
2022/09/23 数据库