Close
升级到 Vue 3 | Vue 2 EOL

Vue 组件单元测试

基本示例

单元测试是软件开发的基础部分。单元测试以隔离的方式执行代码的最小单元,以提高添加新功能和追踪错误的便捷性。Vue 的 单文件组件 使得为组件编写隔离的单元测试变得直截了当。这使您能够自信地开发新功能,确保不会破坏现有功能,并帮助其他开发人员理解您的组件的功能。

这个简单的示例测试是否渲染了一些文本

<template>
<div>
<input v-model="username">
<div
v-if="error"
class="error"
>
{{ error }}
</div>
</div>
</template>

<script>
export default {
name: 'Hello',
data () {
return {
username: ''
}
},

computed: {
error () {
return this.username.trim().length < 7
? 'Please enter a longer username'
: ''
}
}
}
</script>
import { shallowMount } from '@vue/test-utils'
import Hello from './Hello.vue'

test('Hello', () => {
// render the component
const wrapper = shallowMount(Hello)

// should not allow for `username` less than 7 characters, excludes whitespace
wrapper.setData({ username: ' '.repeat(7) })

// assert the error is rendered
expect(wrapper.find('.error').exists()).toBe(true)

// update the name to be long enough
wrapper.setData({ username: 'Lachlan' })

// assert the error has gone away
expect(wrapper.find('.error').exists()).toBe(false)
})

上面的代码片段展示了如何测试基于用户名长度是否渲染错误消息。它演示了 Vue 组件单元测试的一般思路:渲染组件,并断言标记与组件的状态匹配。

为什么要测试?

组件单元测试有很多好处

自动化测试允许大型开发团队维护复杂的代码库。

入门

Vue Test Utils 是用于 Vue 组件单元测试的官方库。 vue-cli webpack 模板附带 Karma 或 Jest,两者都是得到良好支持的测试运行器,并且 Vue Test Utils 文档中有一些 指南

真实世界示例

单元测试应该

让我们继续构建之前的示例,同时介绍 工厂函数 的概念,使我们的测试更紧凑易读。该组件应该

让我们先看看组件代码

<template>
<div>
<div class="message">
{{ message }}
</div>
Enter your username: <input v-model="username">
<div
v-if="error"
class="error"
>
Please enter a username with at least seven letters.
</div>
</div>
</template>

<script>
export default {
name: 'Foo',

data () {
return {
message: 'Welcome to the Vue.js cookbook',
username: ''
}
},

computed: {
error () {
return this.username.trim().length < 7
}
}
}
</script>

我们应该测试的内容是

以及我们第一次尝试的测试

import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'

describe('Foo', () => {
it('renders a message and responds correctly to user input', () => {
const wrapper = shallowMount(Foo, {
data() {
return {
message: 'Hello World',
username: ''
}
}
})

// see if the message renders
expect(wrapper.find('.message').text()).toEqual('Hello World')

// assert the error is rendered
expect(wrapper.find('.error').exists()).toBeTruthy()

// update the `username` and assert error is no longer rendered
wrapper.setData({ username: 'Lachlan' })
expect(wrapper.find('.error').exists()).toBeFalsy()
})
})

上面的代码有一些问题

下面的示例通过以下方式改进了测试

更新后的测试:

import { shallowMount } from '@vue/test-utils'
import Foo from './Foo'

const factory = (values = {}) => {
return shallowMount(Foo, {
data () {
return {
...values
}
}
})
}

describe('Foo', () => {
it('renders a welcome message', () => {
const wrapper = factory()

expect(wrapper.find('.message').text()).toEqual("Welcome to the Vue.js cookbook")
})

it('renders an error when username is less than 7 characters', () => {
const wrapper = factory({ username: '' })

expect(wrapper.find('.error').exists()).toBeTruthy()
})

it('renders an error when username is whitespace', () => {
const wrapper = factory({ username: ' '.repeat(7) })

expect(wrapper.find('.error').exists()).toBeTruthy()
})

it('does not render an error when username is 7 characters or more', () => {
const wrapper = factory({ username: 'Lachlan' })

expect(wrapper.find('.error').exists()).toBeFalsy()
})
})

需要注意的几点

在顶部,我们声明了工厂函数,它将values对象合并到data中,并返回一个新的wrapper实例。这样,我们就不需要在每个测试中重复const wrapper = shallowMount(Foo)。另一个好处是,当更复杂的组件具有您可能希望在每个测试中模拟或存根的方法或计算属性时,您只需要声明一次。

附加上下文

上面的测试相当简单,但在实践中,Vue 组件通常具有您想要测试的其他行为,例如

Vue Test Utils 指南中提供了更完整的示例,展示了此类测试。

Vue Test Utils 和庞大的 JavaScript 生态系统提供了大量工具,可以促进几乎 100% 的测试覆盖率。然而,单元测试只是测试金字塔的一部分。其他类型的测试包括 e2e(端到端)测试和快照测试。单元测试是最小且最简单的测试 - 它们对工作单元进行断言,隔离单个组件的每个部分。

快照测试保存 Vue 组件的标记,并与每次测试运行时生成的新的标记进行比较。如果发生变化,开发人员会收到通知,并可以决定更改是故意的(组件已更新)还是意外的(组件行为不正确)。

端到端测试确保多个组件能够很好地协同工作。它们更高级。一些示例可能是测试用户是否可以注册、登录并更新他们的用户名。这些测试比单元测试或快照测试运行速度慢。

单元测试在开发过程中最有用,无论是帮助开发人员思考如何设计组件,还是重构现有组件,并且通常在每次代码更改时运行。

更高级别的测试,例如端到端测试,运行速度要慢得多。这些测试通常在部署前运行,以确保系统的每个部分都能正常协同工作。

有关测试 Vue 组件的更多信息,请参阅核心团队成员 Edd Yerburgh 编写的 Testing Vue.js Applications

何时避免使用此模式

单元测试是任何严肃应用程序的重要组成部分。最初,当应用程序的愿景尚不明确时,单元测试可能会减慢开发速度,但一旦愿景确立,并且真实用户将与应用程序进行交互,单元测试(以及其他类型的自动化测试)对于确保代码库的可维护性和可扩展性至关重要。