前端Vuer,请收好这份《Vue组件单元测试》宝典,给自己多一些安全感
大家好,我是 Kagol。
作为一名前端,在做业务开发的过程中,你是否曾经:
- 因为担心上线之后出bug,而反复手工验证自己负责的模块
- 不敢修改现有的“屎山”(别人写的或者是自己1年前写的)代码,从而不断地编写if/else
- 发现业务中有很多重复的代码,每次一改好多地方都要改,但又不敢重构,担心重构之后出bug
- 战战兢兢地修复一个陈年bug,就怕引起N个新bug
如果你中了以上任何一条,说明你现在缺乏安全感,你担心、你害怕、你不敢、你战战兢兢、你如履薄冰。
每天写代码都处在担惊受怕当中,程序员的尊严何在!
程序员的安全感要自己给自己,是时候改变现状了!
我们有很多方法可以给自己安全感,比如:
- 配置代码检测工具 ESLint
- 安装拼写检查插件 Code Spell Checker
- 代码评审 Code Review
- 结对编程 Pair programming
- 编写单元测试 Unit Test
本文主要给大家介绍如何在 Vue 项目中编写单元测试。
1 搭环境
我们的单元测试环境基于 vitest
+ @vue/test-utils
。
前提:你需要有一个 Vue 项目,没有的话可以参考 Vite 官网进行创建。
第一步,在你的 Vue 项目中安装必要的依赖包。
npm i -D vitest @vue/test-utils happy-dom @vitest/coverage-v8
在 vite.config.ts
文件中增加以下配置。
import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], // 新增 test: { environment: 'happy-dom' } })
在 package.json
文件中增加相应的脚本命令
"scripts": { "dev": "vite", "build": "vue-tsc && vite build", "preview": "vite preview", // 新增 "test": "vitest" },
我们尝试执行以下命令:
npm test
会发现控制台会打印以下日志:
$ npm test > vue3-vite@0.0.0 test > vitest DEV v0.33.0 /vue3-vite-demo include: **/*.{test,spec}.?(c|m)[jt]s?(x) exclude: **/node_modules/**, **/dist/**, **/cypress/**, **/.{idea,git,cache,output,temp}/**, **/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.* watch exclude: **/node_modules/**, **/dist/** No test files found, exiting with code 1
意思是:没有找到单元测试文件。
除此之外,我们还能获取一些额外的信息,比如 include 表明了单元测试文件的命令格式:
**/*.{test,spec}.?(c|m)[jt]s?(x)
我们在 src/components
目录下创建一个 HelloWorld.spec.ts
文件。
import { mount } from '@vue/test-utils' import { describe, it, expect } from 'vitest' import HelloWorld from './HelloWorld.vue' describe('测试 HelloWorld 组件', () => { it('测试基本功能', async () => { const wrapper = mount(HelloWorld) expect(wrapper.exists()).toBeTruthy() }) })
再次执行 npm test
命令
$ npm test ✓ src/components/HelloWorld.spec.ts (1) ✓ 测试 HelloWorld 组件 (1) ✓ 测试基本功能 Test Files 1 passed (1) Tests 1 passed (1) Start at 23:34:49 Duration 126ms
会提示:有一个单元测试用例通过。
这样我们的 Vue 项目单元测试环境就搭建成功,并且完成了第一个 Vue 单元测试用例🎉🎉
2 测什么
有了单元测试环境,我们可以在其中任意发挥,给自己满满的安全感。
那么我们应该如何给 Vue 组件编写单元测试呢?
我们以 OpenTiny Vue 的 DatePicker 组件为例。
效果图:
我们可以按照以下步骤编写单元测试用例:
Step 1:测试默认行为
- 测试基本功能:点击日期输入框,应该弹出日期选择面板,点击日期选择面板中的日期,面板消失,并在输入框中显示选中的日期
- 测试清除日期:鼠标移到已经选择日期的输入框中,应该出现清除日期的图标按钮,点击清除日期图标,输入框中的日期被清除
- ...
Step 2:测试每一个单独的 API
- 测试 disabled 属性:设置 disabled 属性之后,日期输入框应该变成禁用状态,点击输入框,不会弹出日期选择面板
- 测试 clearable 属性:设置 clearable 为 false 之后,鼠标移到输入框上,不显示清除日期的图标
- ...
Steps 3:测试 API 的边界值
- 测试日期越界:设置 v-model 的值为
"2023-07-32"
,应该不显示日期 - 测试错误格式的日期:设置 v-model 的值为数值
20230713
,应该不显示日期 - ...
Steps 4:测试 API 之间的组合
- 测试 type/format 三个属性之间的组合:设置
type="week"
和format="yyyy 年第 WW 周"
,日期选择面板应该变成选择周,选择5月7日到13日这周之后,输入框中显示的内容应该是2023 年第19周
- ...
<tiny-date-picker v-model="value" type="week" format="yyyy 年第 WW 周" ></tiny-date-picker>
3 怎么测
单测三大件:describe / test / expect
一个单元测试包含三个部分:
- describe 测试套,里面可以包含多个测试用例,
- it(test) 测试用例
- expect 断言语句
import { describe, it, expect } from 'vitest' describe('测试 HelloWorld 组件', () => { it('测试基本功能', async () => { const wrapper = mount(HelloWorld) wrapper. expect(wrapper.exists()).toBeTruthy() expect(wrapper.find('.card').exists()).toBeTruthy() }) it('测试 msg 属性', () => { ... }) })
模拟 Vue 组件挂载:mount 和 wrapper
每个单元测试里面测试 Vue 组件的表现是否正常,需要借助 @vue/test-utils
的 mount 方法,模拟组件的挂载。
import { mount } from '@vue/test-utils' import HelloWorld from './HelloWorld.vue' const wrapper = mount(HelloWorld, { props: { msg: 'OpenTiny' } })
用 mount 函数包裹组件,得到的是一个挂载好的组件对象,该对象包含了一系列实用的方法可以用于组件的测试。
比较常用的有:
- find:寻找组件内部的 DOM 节点
- findComponent:寻找子组件
- exists:判断组件或元素是否存在
- attributes:获取 DOM 节点的属性
- classes:获取 DOM 节点的 class
- ...
更多 wrapper 方法请参考:Vue Test Utils 官网文档
写单测就是写断言
有了 wrapper,就可以对 Vue 组件做断言。
比如以下断言用于判断 DOM 节点 .card
是否存在,toBeTruthy()
用于断言一个值是否为 true。
expect(wrapper.find('.card').exists()).toBeTruthy()
常见的断言类型有:
- toBe:用于断言原始类型是否相等,比如:
expect(1+1).toBe(2)
- toBeTruthy:用于断言一个值是否为 true
- not:用于否定断言,比如:
expect(1+1).toBe(3)
- toBeGreaterThan:断言实际值是否大于接收到的值
- toEqual:断言实际值是否等于接收到的值或具有相同的结构(如果是对象,则递归比较它们),注意和
toBe
的区别 - toContain:断言实际值是否在数组中
- toMatch:断言字符串是否与正则表达式或字符串匹配
- toHaveBeenCalled:用于测试函数是否已被调用
更多断言类型请参考:Vitest 官网
一个 DatePicker 组件的小例子
测试 DatePicker 组件的基本功能:点击日期输入框,应该弹出日期选择面板。
it('测试 DatePicker 组件的基本功能', async () => { const value = '' const wrapper = mount(() => <DatePicker v-model={value}></DatePicker>) expect(wrapper.exists()).toBe(true) // 没有点击日期输入框之前,没有日期选择面板 expect(document.querySelector('.tiny-date-picker')).not.toBeTruthy() await wrapper.find('input').trigger('focus') // 点击日期输入框之后,出现日期选择面板 expect(document.querySelector('.tiny-date-picker')).toBeTruthy() })
3 自己动手实践吧
OpenTiny Vue 正在招募社区贡献者,欢迎加入我们🎉
你可以通过以下方式参与贡献:
你可以根据自己的喜好认领以下类型的任务:
如何贡献单元测试:
- 在
packages/vue
目录下搜索it.todo
关键字,找到待补充的单元测试 - 按照以上指南编写组件单元测试
- 执行单个组件的单元测试:
pnpm test:unit3 button
如果你是一位经验丰富的开发者,想接受一些有挑战的任务,可以考虑以下任务:
- ✨ [Feature]: tree树形控件能增加虚拟滚动功能
- ✨ [Feature]: Tree 组件增加节点连接线
- ✨ [Feature]: 增加视频播放组件
- ✨ [Feature]: 增加思维导图组件
- ✨ [Feature]: 添加类似飞书的多维表格组件
- ✨ [Feature]: 添加到 unplugin-vue-components
- ✨ [Feature]: 兼容formily
参与 OpenTiny 开源社区贡献,你将收获:
直接的价值:
- 通过参与一个实际的跨端、跨框架组件库项目,学习最新的
Vite
+Vue3
+TypeScript
+Vitest
技术 - 学习从 0 到 1 搭建一个自己的组件库的整套流程和方法论,包括组件库工程化、组件的设计和开发等
- 为自己的简历和职业生涯添彩,参与过优秀的开源项目,这本身就是受面试官青睐的亮点
- 结识一群优秀的、热爱学习、热爱开源的小伙伴,大家一起打造一个伟大的产品
长远的价值:
- 打造个人品牌,提升个人影响力
- 培养良好的编码习惯
- 获得华为云 OpenTiny 团队的荣誉和定制小礼物
- 受邀参加各类技术大会
- 成为 PMC 和 Committer 之后还能参与 OpenTiny 整个开源生态的决策和长远规划,培养自己的管理和规划能力
- 未来有更多机会和可能
关于 OpenTiny
OpenTiny 是一套华为云出品的企业级组件库解决方案,适配 PC 端 / 移动端等多端,涵盖 Vue2 / Vue3 / Angular 多技术栈,拥有主题配置系统 / 中后台模板 / CLI 命令行等效率提升工具,可帮助开发者高效开发 Web 应用。
核心亮点:
跨端跨框架
:使用 Renderless 无渲染组件设计架构,实现了一套代码同时支持 Vue2 / Vue3,PC / Mobile 端,并支持函数级别的逻辑定制和全模板替换,灵活性好、二次开发能力强。组件丰富
:PC 端有80+组件,移动端有30+组件,包含高频组件 Table、Tree、Select 等,内置虚拟滚动,保证大数据场景下的流畅体验,除了业界常见组件之外,我们还提供了一些独有的特色组件,如:Split 面板分割器、IpAddress IP地址输入框、Calendar 日历、Crop 图片裁切等配置式组件
:组件支持模板式和配置式两种使用方式,适合低代码平台,目前团队已经将 OpenTiny 集成到内部的低代码平台,针对低码平台做了大量优化周边生态齐全
:提供了基于 Angular + TypeScript 的 TinyNG 组件库,提供包含 10+ 实用功能、20+ 典型页面的 TinyPro 中后台模板,提供覆盖前端开发全流程的 TinyCLI 工程化工具,提供强大的在线主题配置平台 TinyTheme
欢迎加入 OpenTiny 开源社区。
添加微信小助手:opentiny-official,一起参与共建!
OpenTiny 官网:https://opentiny.design/
Vue组件库:https://opentiny.design/tiny-vue
Angular组件库:https://opentiny.design/tiny-ng
OpenTiny 代码仓库:https://github.com/opentiny/ (欢迎 Star ⭐)
往期文章推荐
- 🎉OpenTiny Vue 3.9.0 版本发布:新增3个新组件、支持 SSR
- 🎉OpenTiny 3.8.0 正式发布:推出「极客黑」新主题!
- 🌈使用 TinyCLI 两行命令创建一个美观大气的 Admin 系统
- 🌈一个 OpenTiny,Vue2 Vue3 都支持!
- 🌈历史性的时刻!OpenTiny 跨端、跨框架组件库正式升级 TypeScript,10 万行代码重获新生!
参考:

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
用户案例 | Apache DolphinScheduler 离线调度在自如多业务场景下的应用与实践
用户案例 | 自如 随着自如业务的快速发展,不断增长的调度任务和历史逾万的存量任务对平台稳定性提出了更高的要求。同时,众多非专业开发人员也需要一种更为“亲民”的调度平台使用体验。 如何满足这些日渐凸显的需求对自如大数据平台的开发团队来说,无疑是巨大的挑战。团队经过深入的研究和对比,发现Apache DolphinScheduler是一个能够满足自如当前所有核心需求的项目。 至此,团队开始引入Apache DolphinScheduler,并在此基础上进行了一系列的改造和优化,其中包括自动生成SQL血缘解析调度,支持Ambari管理Apache DolphinScheduler,以及端到端调度组件的可用性监控等功能,从而更好地满足企业内需求。 本文将详细描绘Apache DolphinScheduler在自如中的应用以及演变过程。 作者简介 陈卓宇,自如大数据平台运维,负责自如离线数据调度,Apache StreamPark PPMC,Apache DolphinScheduler Contributor 业务挑战 复杂的业务场景:自如的数据处理业务场景丰富多样,涵盖了To C和To B...
- 下一篇
GaussDB OLTP云数据库配套工具DDM
目录 一、前言 二、DDM定义 三、DDM业务架构 四、为什么需要DDM? 五、DDM特性 六、DDM应用场景 一、前言 现在越来越多的企业应用在逐步向云平台迁移,同时这对云平台带了一个严峻的考验和挑战。但针对华为云GaussDB数据库, 我们在生态方面做了比较健全的建设,同时自研了很多相应的原生态工具。本文我们主要介绍一下GaussDB 云数据库的配套工具DDM。 二、DDM定义 DDM(Distributed Database Middleware),是由华为云自主研发的云原生分布式数据库中间件,以服务的方式为应用提供对多个数据库实例进行分布式透明访问。彻底解决数据库可扩展性问题,实现海量数据的存储和高并发访问。 三、DDM业务架构 DDM业务架构(来源华为云官网): DDM业务架构:将底层的数据库引擎进行一个分布式的集中管理。应用服务访问DDM实例即可,无需关心底层分片式的数据库,所有的业务逻辑等都有DDM路由分发,从而让应用透明访问。 作为管理员,可以通过DDM的控制台进行图形化管理,比如实例管理、平滑扩容、逻辑库管理等。 作为开发人员,可以将开发的应用程序通过DDM控制台进行...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19