书接上文, karma+webpack 搭建 vue 单元测试环境介绍了 vue 单元测试环境搭建及查看源文件的测试覆盖覆盖率. 今天来说一下 vue 单元测试思路和 case 的写法. 测试框架使用 jasmine, 语法参考 https://jasmine.github.io/2.0/introduction.html .
代码地址: https://github.com/MarxJiao/vue-karma-test/tree/spec-demo
测试关注点
对于 vue 组件, 单元测试测试主要关注以下几点:
vue 组件加载后, 各数据模型是否符合预期
定义的方法是否可用
filter 是否可用
带有 props 的组件, 数据能否正常传递
异步更新 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 官方提供的方法 https://vuejs.org/v2/guide/unit-testing.html#Writing-Testable-Components
使用 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 官网的示例 https://vuejs.org/v2/guide/unit-testing.html#Asserting-Asynchronous-Updates
使用 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 组件单元测试的用例编写的介绍, 例子举得比较简单, 主要是介绍各种情况的测试方法.
相关链接
karma+webpack 搭建 vue 单元测试环境
Vue 官网单元测试介绍 https://cn.vuejs.org/v2/guide/unit-testing.html
Jasmine introduction https://jasmine.github.io/2.0/introduction.html
来源: http://www.jb51.net/article/140742.htm