8

本文基于vue-webpack-boilerplate。官方推荐使用Karma+Mocha+Chai来进行单元测试。

介绍

Karma:一个测试运行器,用于启动浏览器,运行测试案例并将结果报告给我们。该工具的主要作用是将项目运行在各种主流Web浏览器进行测试。

Mocha:一个测试框架。可结合chai断言库使用。

Chai:一个测试断言库,提供了更好的断言语法。所谓断言,就是对组件做一些操作,并预言产生的结果。如果测试结果与断言相同则测试通过。Chai断言库中,to be been is that which and has have with at of same but does这些语言链是没有意义的,只是便于理解而已。

实践

组件无依赖,无props

对于无需导入任何依赖,也没有props的,直接编写测试案例即可。

MyComponent.vue

<template>
  <span>{{ message }}</span>
</template>
<script>
  export default {
    data () {
      return {
        message: 'hello!'
      }
    },
    created () {
      this.message = 'bye!'
    }
  }
</script>

MyComponent.spec.js

// 导入 Vue.js 和组件,进行测试
import Vue from 'vue'
import MyComponent from 'path/to/MyComponent.vue'

describe('MyComponent', () => {
  // 检查原始组件选项
  it('has a created hook', () => {
    expect(typeof MyComponent.created).to.eql('function')
  })
})

组件有props

对于组件需要props,编写单元测试时,通过propsData传递该参数。

MyComponent.vue

<template>
  <p>{{ msg }}</p>
</template>
<script>
  export default {
    props: ['msg']
  }
</script>

MyComponent.spec.js

import Vue from 'vue'
import MyComponent from 'path/to/MyComponent.vue'

function getRenderedText (Component, propsDataMsg) {
  const Ctor = Vue.extend(Component)
  const vm = new Ctor({ propsData: propsDataMsg}).$mount()
  return vm.$el.textContent
}
describe('MyComponent', () => {
  it('renders correctly with different props', () => {
    expect(getRenderedText(MyComponent, {
      msg: 'Hello'
    })).to.eql('Hello')
    expect(getRenderedText(MyComponent, {
      msg: 'Bye'
    })).to.eql('Bye')
  })
})

组件有依赖

若组件存在依赖,则可通过inject-loader解决。inject-loader可将任意依赖项注入到*.vue组件中。

MyComponent.vue

<template>
  <div class="msg">{{ msg }}</div>
</template>

<script>
// this dependency needs to be mocked
import SomeService from '../service'

export default {
  data () {
    return {
      msg: SomeService.msg
    }
  }
}
</script>

MyComponent.spec.js

//“!!”表示禁用全局配置的所有loaders。“vue-loader?inject!”表示使用vue-loader,传入inject参数。
const ExampleInjector = require('!!vue-loader?inject!./example.vue')
//运行ExampleInjector函数返回一个MyComponent的实例,该实例中MyComponent组件的依赖项已被模拟。
const ExampleWithMocks = ExampleInjector({
  // mock it
  '../service': {
    msg: 'Hello from a mocked service!'
  }
})

describe('MyComponent', () => {
  it('should render', () => {
    const vm = new Vue({
      template: '<div><test></test></div>',
      components: {
        'test': ExampleWithMocks
      }
    }).$mount()
    expect(vm.$el.querySelector('.msg').textContent).to.eql('Hello from a mocked service!')
  })
})

异步操作

对于异步操作,it块执行的时候,需要传入一个回调函数,通常该函数被命名为done。当测试结束的时候,必须显式调用这个函数,告诉Mocha测试结束了。否则,Mocha就无法知道,测试是否结束,会一直等到超时报错。

// 在状态更新后检查生成的 HTML
it('updates the rendered message when vm.message updates', done => {
  const vm = new Vue(MyComponent).$mount()
  vm.message = 'foo'
  // 在状态改变后和断言 DOM 更新前等待一刻
  Vue.nextTick(() => {
    expect(vm.$el.textContent).to.eql('foo')
    done()
  })
})

npm run unit

执行 npm run unit 命令运行单元测试。会产生结果列表:

clipboard.png

若想看测试覆盖率等情况,可在test/unit/coverage查看。

注意

  • 测试脚本都放在 test/unit/specs/ 目录下。

  • 脚本命名方式是[组件名].spec.js。

  • 在karma.conf.js文件里修改karma配置。

  • 单元测试默认测试 src 目录下除了 main.js 之外的所有文件,可在 test/unit/index.js 文件中修改。

  • 测试脚本里面应该包括一个或多个describe块,每个describe块应该包括一个或多个it块。

    • describe块称为"测试套件"(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称("加法函数的测试"),第二个参数是一个实际执行的函数。

    • it块称为"测试用例"(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称("1 加 1 应该等于 2"),第二个参数是一个实际执行的函数。

  • Mocha在describe块之中,提供测试用例的四个钩子:before()、after()、beforeEach()和afterEach()。它们会在指定时间执行。

参考:
单元测试
Testing with Mocks
Unit Testing
测试框架 Mocha 实例教程
Chai


lijinxieyang
356 声望13 粉丝