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

Vue.js TDD期间Vue实例上的模拟方法,vue.js,vuejs2,tdd,jestjs,vue-test-utils,Vue.js,Vuejs2,Tdd,Jestjs,Vue Test Utils,我在构建Vue应用程序的同时学习TDD,并试图遵守严格的法规,只编写足够的生产代码来满足失败的单元测试。我真的很喜欢这种方法,但在向Vue实例添加方法以及测试在从模板中的元素触发事件时是否调用了方法方面遇到了障碍 我找不到任何关于如何模拟Vue方法的建议,因为如果我模拟代理方法,它最终不会被调用(我使用的是Jest和Vue测试Utils) 我也在使用Cypress,所以我可以在e2e中填写这个测试,但我希望能够用单元测试尽可能多地覆盖 我拥有Edd Yerburgh的《测试Vue.js应用程序》

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

我找不到任何关于如何模拟Vue方法的建议,因为如果我模拟代理方法,它最终不会被调用(我使用的是Jest和Vue测试Utils)

我也在使用Cypress,所以我可以在e2e中填写这个测试,但我希望能够用单元测试尽可能多地覆盖

我拥有Edd Yerburgh的《测试Vue.js应用程序》一书,但在关于测试组件方法的一节中,他简单地陈述了以下内容:

通常,组件在内部使用方法。例如,要在单击按钮时登录控制台[…],您可以将这些方法视为私有方法,它们不打算在组件外部使用。私有方法是实现细节,所以您不直接为它们编写测试

这种方法显然不允许遵循更严格的TDD法律,那么TDD纯粹主义者是如何处理的呢

ButtonComponent.vue


点击我
导出默认值:{
方法:{
方法(){
//有人叫我吗?
}
}
}
ButtonComponent.spec.js

it('单击时将调用该方法',()=>{
常量包装=浅装(按钮组件)
const mockMethod=jest.fn()
wrapper.vm.method=mockMethod
const button=wrapper.find('按钮')
button.vm.$emit('单击')
expect(mockMethod).toHaveBeenCalled()
//预期已调用模拟函数,但未调用该函数
})
解决方案1:
jest.spyOn(Component.methods,'METHOD\u NAME')
在安装之前,可以使用模拟组件方法:

从'@/components/MyComponent.vue'导入MyComponent
描述('MyComponent',()=>{
它('click does',async()=>{
const mockMethod=jest.spyOn(MyComponent.methods,'doSomething')
等待shallowMount(MyComponent)。查找('button')。触发('click'))
expect(mockMethod).toHaveBeenCalled()
})
})
解决方案2:将方法移动到可以模拟的单独文件中 并使用Jest的Variable来模拟被测试组件调用的抽象模块

例如,要验证是否调用了
单击
-处理程序,请执行以下操作:

  • 单击
    -处理程序的主体移动到共享JavaScript文件中
  • 将共享模块导入正在测试的组件和您的测试中(确保在这两种情况下使用相同的导入路径)
  • 调用
    jest.mock()
    模拟共享模块的导出函数
  • 重置测试套件中的模拟。只有当套件中有多个测试时,这才有必要
  • /@/components/MyComponent/utils.js
    导出函数doSomething(){/*…*/}//1️⃣
    //@/components/MyComponent/MyComponent.vue()
    从“@/components/MyComponent/utils”导入{doSomething}//2️⃣
    导出默认值{
    方法:{
    onClick(){
    doSomething()//1️⃣
    }
    }
    }
    //@/test/MyComponent.spec.js
    从“@/components/MyComponent/utils”导入{doSomething}//2️⃣
    jest.mock('@/components/MyComponent/utils')//3️⃣
    描述('MyComponent',()=>{
    beforeach(()=>doSomething.mockClear())/4️⃣
    它('click does',async()=>{
    等待shallowMount(MyComponent)。查找('button')。触发('click'))
    期望(doSomething)被调用
    })
    })
    
    解决方案3:
    setMethods()
    (v1.0之前) 使用
    setMethods()
    ()覆盖组件方法:

    description('MyComponent',()=>{
    它('click does',async()=>{
    //备选方案A:
    const mockMethod=jest.fn()
    常量包装=浅量(MyComponent)
    setMethods({doSomething:mockMethod})
    等待包装器。查找('button')。触发('click'))
    expect(mockMethod).toHaveBeenCalled()
    //备选案文B:
    const mockMethod=jest.fn()
    常量包装=浅量(MyComponent{
    方法:{
    剂量测定法
    }
    })
    等待包装器。查找('button')。触发('click'))
    expect(mockMethod).toHaveBeenCalled()
    })
    })
    

    正如tony19所提到的,使用spyOn方法将适合您。我还发现我需要在模板中的方法中添加括号
    ()
    ,以便提取它。我通过了以下文件的测试:

    ButtonComponent.vue

    <template>
      <button @click="method()">Click me</button>
    </template>
    
    <script>
    export default {
      methods: {
        method() {
          // Have I been called?
        }
      }
    }
    </script>
    
    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
    })