TDD期间Vue实例上的模拟方法

时间:2018-12-16 04:36:02

标签: vue.js vuejs2 tdd jestjs vue-test-utils

我在构建Vue应用程序时正在学习TDD,并尝试遵守严格的法律,即仅编写足够的生产代码来满足失败的单元测试。我真的很喜欢这种方法,但是在向Vue实例添加方法并测试事件是否从模板中的元素触发时调用方法方面遇到了障碍。

鉴于如何模拟Vue方法,我找不到任何建议,因为如果模拟代理方法,最终将不会被调用(我正在使用Jest和Vue Test Utils)。

我也在使用赛普拉斯(Cypress),所以我可以在e2e中填写此测试,但我希望能够涵盖更多的单元测试。

我拥有Edd Yerburgh的《 Testing Vuejs Applications》一书,但在有关测试组件方法的部分中,他只是简单地陈述了以下内容:

“”通常,组件在内部使用方法。例如,单击按钮时登录到控制台。.......您可以将它们视为私有方法-不应在外部使用它们私有方法是实现细节,因此您不必直接为它们编写测试。“

这种方法显然不允许遵循更严格的TDD法则,那么TDD纳粹如何处理呢?

感谢您的时间。

// ButtonComponent.vue

<template>
    <button @click="method">Click me</button>
</template>

<script>
    export default: {
        methods: {
            method () {
                // Have I been called?
            }
        }
    }
</script>

这是我的测试,如果有帮助的话:

// ButtonComponent.spec.js

it('will call the method when clicked, () => {

    const wrapper = shallowMount(ButtonComponent)

    const mockMethod = jest.fn()

    wrapper.vm.method = mockMethod

    const button = wrapper.find('button')

    button.vm.$emit('click')

    expect(mockMethod).toHaveBeenCalled()
    // Expected mock function to have been called, but it was not called
})

2 个答案:

答案 0 :(得分:1)

一些问题:

  1. 您的click事件处理程序未在模板中正确绑定。 syntax for binding event handlers是:

    @EVENTNAME=METHOD (shorthand for v-on:EVENTNAME=METHOD)
    

    但是您使用了属性绑定语法:

    :PROPERTY=VALUE (shorthand for v-bind:PROPERTY:VALUE)
    

    从v2.5.17开始,Vue不会发出有关此类错误的错误/警告,因此很容易错过这一点。您的绑定应如下所示:

    <button @click="method">Click me</button>
    
  2. 您的测试应在覆盖组件方法时使用Vue Test Utils setMethods() API,如docs example(实际上与您的用例完全匹配)所示:

    const mockMethod = jest.fn()
    // wrapper.vm.method = mockMethod  // DON'T DO THIS
    wrapper.setMethods({ method: mockMethod })
    
  3. 测试包装器没有$emit()方法,如果尝试这样做,则会遇到运行时错误。您可能打算使用trigger() API:

    const button = wrapper.find('button')
    // button.$emit('click')  // DON'T DO THIS
    button.trigger('click')
    

demo

答案 1 :(得分:0)

正如 tony19 提到的,使用 spyOn 方法对你有用。我还发现我需要在模板中的方法中添加括号 () 才能被选中。我通过以下文件通过了测试:

ButtonComponent.vue

<template>
  <button @click="method()">Click me</button>
</template>

<script>
export default {
  methods: {
    method() {
      // Have I been called?
    }
  }
}
</script>

ButtonComponent.spec.js

import ButtonComponent from '@/components/ButtonComponent'
import { shallowMount } from '@vue/test-utils'

it('will call the method when clicked', () => {
  const wrapper = shallowMount(ButtonComponent)
  const mockMethod = jest.spyOn(wrapper.vm, 'method')

  const button = wrapper.find('button')
  button.trigger('click')

  expect(mockMethod).toHaveBeenCalled()
  // passes
})