测试

    我们主要想针对 Vuex 中的 mutation 和 action 进行单元测试。

    Mutation 很容易被测试,因为它们仅仅是一些完全依赖参数的函数。这里有一个小技巧,如果你在 文件中定义了 mutation,并且使用 ES2015 模块功能默认输出了 Vuex.Store 的实例,那么你仍然可以给 mutation 取个变量名然后把它输出去:

    下面是用 Mocha + Chai 测试一个 mutation 的例子(实际上你可以用任何你喜欢的测试框架):

    1. // mutations.js
    2. export const mutations = {
    3. increment: state => state.count++
    4. }
    1. // mutations.spec.js
    2. import { expect } from 'chai'
    3. import { mutations } from './store'
    4. // 解构 `mutations`
    5. const { increment } = mutations
    6. describe('mutations', () => {
    7. it('INCREMENT', () => {
    8. // 模拟状态
    9. const state = { count: 0 }
    10. // 应用 mutation
    11. increment(state)
    12. // 断言结果
    13. expect(state.count).to.equal(1)
    14. })
    15. })

    下面是一个测试异步 action 的例子:

    1. // actions.spec.js
    2. // 使用 require 语法处理内联 loaders。
    3. // inject-loader 返回一个允许我们注入 mock 依赖的模块工厂
    4. import { expect } from 'chai'
    5. const actionsInjector = require('inject-loader!./actions')
    6. // 使用 mocks 创建模块
    7. const actions = actionsInjector({
    8. '../api/shop': {
    9. getProducts (cb) {
    10. setTimeout(() => {
    11. cb([ /* mocked response */ ])
    12. }, 100)
    13. }
    14. }
    15. })
    16. // 用指定的 mutations 测试 action 的辅助函数
    17. const testAction = (action, args, state, expectedMutations, done) => {
    18. // 模拟提交
    19. const commit = (type, payload) => {
    20. const mutation = expectedMutations[count]
    21. try {
    22. if (payload) {
    23. expect(mutation.payload).to.deep.equal(payload)
    24. }
    25. } catch (error) {
    26. done(error)
    27. }
    28. count++
    29. if (count >= expectedMutations.length) {
    30. done()
    31. }
    32. }
    33. // 用模拟的 store 和参数调用 action
    34. action({ commit, state }, ...args)
    35. // 检查是否没有 mutation 被 dispatch
    36. if (expectedMutations.length === 0) {
    37. expect(count).to.equal(0)
    38. done()
    39. }
    40. }
    41. describe('actions', () => {
    42. it('getAllProducts', done => {
    43. testAction(actions.getAllProducts, [], {}, [
    44. { type: 'REQUEST_PRODUCTS' },
    45. { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }
    46. ], done)
    47. })
    48. })

    如果在测试环境下有可用的 spy (比如通过 Sinon.JS),你可以使用它们替换辅助函数 testAction

    1. describe('actions', () => {
    2. it('getAllProducts', () => {
    3. const commit = sinon.spy()
    4. const state = {}
    5. actions.getAllProducts({ commit, state })
    6. expect(commit.args).to.deep.equal([
    7. ['REQUEST_PRODUCTS'],
    8. ['RECEIVE_PRODUCTS', { /* mocked response */ }]
    9. })
    10. })

    如果你的 getter 包含很复杂的计算过程,很有必要测试它们。Getter 的测试与 mutation 一样直截了当。

    1. // getters.spec.js
    2. import { expect } from 'chai'
    3. import { getters } from './getters'
    4. describe('getters', () => {
    5. it('filteredProducts', () => {
    6. // 模拟状态
    7. const state = {
    8. products: [
    9. { id: 1, title: 'Apple', category: 'fruit' },
    10. { id: 2, title: 'Orange', category: 'fruit' },
    11. { id: 3, title: 'Carrot', category: 'vegetable' }
    12. ]
    13. }
    14. // 模拟 getter
    15. const filterCategory = 'fruit'
    16. // 获取 getter 的结果
    17. const result = getters.filteredProducts(state, { filterCategory })
    18. // 断言结果
    19. expect(result).to.deep.equal([
    20. { id: 1, title: 'Apple', category: 'fruit' },
    21. { id: 2, title: 'Orange', category: 'fruit' }
    22. ])
    23. })
    24. })

    如果你的 mutation 和 action 编写正确,经过合理地 mocking 处理之后这些测试应该不依赖任何浏览器 API,因此你可以直接用 webpack 打包这些测试文件然后在 Node 中执行。换种方式,你也可以用 mocha-loader 或 Karma + karma-webpack在真实浏览器环境中进行测试。

    在 Node 中执行测试

    创建以下 webpack 配置(配置好 .babelrc):

    1. // webpack.config.js
    2. module.exports = {
    3. entry: './test.js',
    4. output: {
    5. path: __dirname,
    6. filename: 'test-bundle.js'
    7. },
    8. module: {
    9. loaders: [
    10. {
    11. test: /\.js$/,
    12. loader: 'babel-loader',
    13. exclude: /node_modules/
    14. }
    15. ]
    16. }
    17. }

    然后:

    在浏览器中测试

    • 安装 mocha-loader
    • 把上述 webpack 配置中的 entry 改成 'mocha-loader!babel-loader!./test.js'
    • 访问 localhost:8080/webpack-dev-server/test-bundle

    使用 Karma + karma-webpack 在浏览器中执行测试