【问题标题】:Vue.js unit test - mock service with async dataVue.js 单元测试 - 使用异步数据模拟服务
【发布时间】:2018-04-01 02:25:04
【问题描述】:

项目:https://github.com/marioedgar/webpack-unit-test

我有一个使用 vue CLI 生成的 Vue.js 应用程序。我只是稍微编辑了 HelloWorld 组件以从我的测试服务中获取一些异步数据,您可以在这里看到:

<template>
  <h1>{{ message }}</h1>
</template>

<script>
  import service from './test.service'
  export default {
    name: 'HelloWorld',
    created () {
      service.getMessage().then(message => {
        this.message = message
      })
    },
    data () {
      return {
        message: 'A'
      }
    }
  }
</script>
<style scoped>
</style>

测试服务在同一个目录下,非常简单:

class Service {
  getMessage () {
    return new Promise((resolve, reject) => {
      console.log('hello from test service')
      resolve('B')
    })
  }
}

const service = new Service()
export default service

所以为了模拟这个服务,我使用 webpack vue-loader 来注入模拟服务,如官方文档中所述:

https://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html

所以这是我的测试,几乎与示例相同:

import Vue from 'vue'
const HelloInjector = require('!!vue-loader?inject!../../../src/components/HelloWorld')

const Hello = HelloInjector({
  // mock it
  './test.service': {
    getMessage () {
      return new Promise((resolve, reject) => {
        resolve('C')
      })
    }
  }
})

describe('HelloWorld.vue', () => {
  it('should render', () => {
    const vm = new Vue({
      template: '<div><test></test></div>',
      components: {
        'test': Hello
      }
    }).$mount()
    expect(vm.$el.querySelector('h1').textContent).to.equal('C')
  })
})

我面临两个问题:

  1. 测试失败,因为断言在模拟的 Promise 解决之前执行。据我了解,这是因为当我进行断言时,vue 生命周期还没有完全完成。等待下一个周期的常见模式是将我的断言包装在下一个刻度函数周围,如下所示:

  it('should render', (done) => {
    const vm = new Vue({
      template: '<div><test></test></div>',
      components: {
        'test': Hello
      }
    }).$mount()
    Vue.nextTick(() => {
      expect(vm.$el.querySelector('h1').textContent).to.equal('C')
      done()
    })
  })

但是,除非我嵌套 3 个 nextTicks,否则这不起作用,这对我来说似乎非常 hacky。有什么我想念的东西来让它工作吗?这个例子看起来非常简单,但是如果没有很多 nextTicks,我就无法通过这个测试

  1. 我不断收到一个奇怪的错误,间歇性地...此警告可能出现 50% 的时间,而且完全不一致。

[vue warn] 组件挂载失败:模板或渲染函数未定义

同样,这种情况只是偶尔发生。我可以在不做任何更改的情况下运行完全相同的单元测试,并且它会在 50% 的情况下向我显示此消息。

【问题讨论】:

标签: unit-testing vue.js


【解决方案1】:

我真的不明白为什么有时组件无法安装。我什至不确定它是否与喷油器有关,但无论如何,我通过不使用它来保持测试的一致性;尝试不同的方法。

如果服务是通过props 注入而不是直接使用,则该组件可能更具可测试性。

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

<script>
  import service from './test.service'

  export default {
    name: 'HelloWorld',
    created () {
      this.service.getMessage().then(message => {
        this.message = message
      })
    },
    data () {
      return {
        message: 'A'
      }
    },
    props: {
      service: {
        default: service
      }
    }
  }
</script>
<style scoped>
</style>

这使得注入器变得不必要,因为可以在构造函数中使用 propsData 将模拟服务传递给组件。

import Vue from 'vue'

import Async from '@/components/Async'

const service = {
  getMessage () {
    return new Promise((resolve, reject) => {
      resolve('C')
    })
  }
}

describe('Async.vue', () => {
  let vm
  before(() => {
    const Constructor = Vue.extend(Async)
    vm = new Constructor({
      propsData: {
        service: service
      }
    }).$mount()
  })
  it('should render', function () {
    // Wrapping the tick inside a promise, bypassing PhantomJS's lack of support
    return (new Promise(resolve => Vue.nextTick(() => resolve()))).then(() => {
      expect(vm.$el.querySelector('h1').textContent).to.equal('C')
    })
  })
})

【讨论】:

  • 我确实比使用注射器更喜欢这个,这确实解决了我面临的问题之一。不幸的是,额外的刻度是必要的。我想知道是否可以在 before() 中这样做以避免每次测试中的所有这些额外代码。那或者我可以添加一个简单的异步辅助函数。
  • 你是对的。使用 mocha 的 before 测试仅在组件完全安装之前进入,因此只需要打勾。我更改了代码以反映这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-20
  • 2014-01-18
  • 2019-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多