

文章目录
正文
1. Vue 单元测试简介
单元测试是确保代码质量和可维护性的重要手段,在 Vue 应用开发中,Jest 和 Vue Test Utils 是最常用的测试工具组合。
1.1 为什么需要单元测试
- 提早发现 bug,减少线上问题
- 重构代码时提供安全保障
- 作为代码的活文档,帮助理解组件功能
- 促进更好的代码设计和模块化
1.2 测试工具介绍
- Jest: Facebook 开发的 JavaScript 测试框架,提供断言库、测试运行器和覆盖率报告
- Vue Test Utils: Vue.js 官方的单元测试实用工具库,提供挂载组件和与之交互的方法
2. 环境搭建
2.1 安装依赖
# 使用 Vue CLI 创建项目时选择单元测试
vue create my-project
# 或在现有项目中安装
npm install --save-dev jest @vue/test-utils vue-jest babel-jest
2.2 配置 Jest
在 package.json 中添加 Jest 配置:
{
"jest": {
"moduleFileExtensions": [
"js",
"vue"
],
"transform": {
"^.+\\.vue$": "vue-jest",
"^.+\\.js$": "babel-jest"
},
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"testMatch": [
"**/tests/unit/**/*.spec.[jt]s?(x)"
],
"collectCoverage": true,
"collectCoverageFrom": [
"src/**/*.{js,vue}",
"!src/main.js",
"!src/router/index.js",
"!**/node_modules/**"
]
}
}
3. 编写第一个测试
3.1 组件示例
假设有一个简单的计数器组件 Counter.vue:
<template>
<div>
<span class="count">{
{ count }}</span>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count += 1
},
decrement() {
this.count -= 1
}
}
}
</script>
3.2 编写测试用例
创建 tests/unit/Counter.spec.js 文件:
import {
mount } from '@vue/test-utils'
import Counter from '@/components/Counter.vue'
describe('Counter.vue', () => {
it('初始计数为0', () => {
const wrapper = mount(Counter)
expect(wrapper.find('.count').text()).toBe('0')
})
it('点击增加按钮后计数加1', async () => {
const wrapper = mount(Counter)
await wrapper.findAll('button').at(0).trigger('click')
expect(wrapper.find('.count').text()).toBe('1')
})
it('点击减少按钮后计数减1', async () => {
const wrapper = mount(Counter)
await wrapper.findAll('button').at(1).trigger('click')
expect(wrapper.find('.count').text()).toBe('-1')
})
})
3.3 运行测试
npm run test:unit
4. Vue Test Utils 核心 API
4.1 挂载组件
// 完全挂载组件及其子组件
const wrapper = mount(Component, {
propsData: {
/* 组件 props */ },
data() {
/* 覆盖组件数据 */ },
mocks: {
/* 模拟全局对象 */ },
stubs: {
/* 替换子组件 */ }
})
// 只挂载当前组件,不渲染子组件
const wrapper = shallowMount(Component, options)
4.2 常用断言和操作
// 查找元素
wrapper.find('div') // CSS 选择器
wrapper.find('.class-name')
wrapper.find('[data-test="id"]')
wrapper.findComponent(ChildComponent)
// 检查内容和属性
expect(wrapper.text()).toContain('Hello')
expect(wrapper.html()).toContain('<div>')
expect(wrapper.attributes('id')).toBe('my-id')
expect(wrapper.classes()).toContain('active')
// 触发事件
await wrapper.find('button').trigger('click')
await wrapper.find('input').setValue('new value')
// 访问组件实例
console.log(wrapper.vm.count) // 访问数据
wrapper.vm.increment() // 调用方法
// 更新组件
await wrapper.setProps({
color: 'red' })
await wrapper.setData({
count: 5 })
5. 测试组件交互
5.1 测试用户输入
假设有一个表单组件 Form.vue:
<template>
<form @submit.prevent="submitForm">
<input v-model="username" data-test="username" />
<input type="password" v-

最低0.47元/天 解锁文章
598

被折叠的 条评论
为什么被折叠?



