参考资料:
1. 单元测试 Vitest 是一个针对单元测试的框架,它由 Vue / Vite 团队成员开发和维护。主要用于测试函数、类、方法等逻辑结果。
提示:Vitest 需要 Vite >=v5.0.0 和 Node >=v20.0.0
官网:https://cn.vitest.dev/
1.1 安装 安装:npm i vitest -D
-D 针对开发环境下使用。
1.2 配置 package.json - 添加 "test": "vitest",
1 2 3 4 5 6 7 8 9 10 11 12 13 14 { ... "scripts" : { "test" : "vitest" , "dev" : "vite" , "build" : "vite build" , "preview" : "vite preview" } , "dependencies" : { ... } , "devDependencies" : { ... "vitest" : "^4.0.16" } }
1.3 启动验证
如果报错:TypeError: crypto.getRandomValues is not a function
具体原因:crypto.getRandomValues() 用于生成加密级安全的随机数,Vite 在生成随机 ID 时会调用它。但该 API 在 Node.js 19+ 才原生支持
1 2 3 4 5 6 7 8 9 > node -v v16.20.2 > nvm list 20.15.0 * 16.20.2 (Currently using 64-bit executable) > nvm use 20.15.0 Now using node v20.15.0 (64-bit) > node -v v20.15.0
将 node 通过 nvm 升级到 19+ 版本即可解决问题。
1 2 3 4 5 6 7 8 9 > npm test myappvite-elementplus@0.0.0 test vitest DEV v4.0.16 E:/work/webProjects/vue/3.0/myappvite-elementplus No test files found. You can change the file name pattern by pressing "p" include: **/*.{test ,spec}.?(c|m)[jt]s?(x) exclude: **/node_modules/**, **/.git/**
include,包含的测试文件规则,如 src/test/1.test.js 即符合文件命名规则
exclude,排除掉的目标测试文件规则
按 q 可以退出测试,不退出的情况下可以一直进行动态测试,修改内容即可立即生效自动测试。
1.4 添加测试文件 参考 vue 官方测试文档:https://cn.vuejs.org/guide/scaling-up/testing.html#unit-testing
目录:
1 2 3 4 src/ test/ 1.test.js moduleA.js
moduleA.js
1 2 3 4 5 6 export function increment (current, max = 10 ) { if (current < max) { return current + 1 } return current }
1.test.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { describe, test, expect } from 'vitest' import { increment } from './moduleA' describe ('测试 increment 方法' , () => { test ('将当前数字加 1' , () => { expect (increment (0 , 10 )).toBe (1 ) }) test ('不会将当前数量增加到超过最大数量' , () => { expect (increment (10 , 10 )).toBe (10 ) }) test ('默认最大值为 10' , () => { expect (increment (10 )).toBe (10 ) }) })
保存直接自动测试,PASS没有报错,测试完成。
1.5 测试验证 以 pinia 的 strore 为例,作为验证:
2.test.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import { describe, test, expect, beforeEach } from 'vitest' import { createPinia, setActivePinia } from 'pinia' import useNewsStore from '../store/newsStore' describe ('测试 pinia newsStore' , () => { let store beforeEach (() => { setActivePinia (createPinia ()) store = useNewsStore () }) test ('测试 newsStore 的 addNews 方法' , () => { expect (store.newsList ).toEqual ([]) const newsItem = { title : "标题111" , type : "keji" , desc : "这是新闻111的内容2222" , } store.addNews (newsItem) expect (store.newsList ).toEqual ([{ title : "标题111" , type : "keji" , desc : "这是新闻111的内容2222" , }]) newsItem.title = "修改后的标题" expect (store.newsList [0 ].title ).toBe ("标题111" ) }) })
newsStore.js - 基于 pinia 的 store
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import { defineStore } from "pinia" ;import { ref } from "vue" ;const useNewsStore = defineStore ('news' , () => { const newsList = ref ([]) const addNews = (value ) => { newsList.value .push ({...value}) } return { newsList, addNews } })export default useNewsStore
1.6 测试异步 1 2 3 4 5 6 test ('测试 cinemaStore 异步请求' , async () => { expect (cinemaStore.cinemaList .length ).toBe (0 ) await cinemaStore.getCinemaList () console .log (cinemaStore.cinemaList .length ) expect (cinemaStore.cinemaList .length ).gt (0 ) })
2. 组件测试 组件测试主要捕捉组件中的 prop、事件、提供的插槽、样式、CSS class名,生命周期钩子 和 其他相关问题。
即 像用户那样点击一个元素,而不是编程式地与组件进行交互。
2.1 安装 安装:npm i -D @testing-library/vue jsdom
-D 针对开发环境下使用。
安装后 package.json
1 2 3 4 5 6 7 { ... "devDependencies" : { "@testing-library/vue" : "^8.1.0" , ... } }
2.2 配置 为了让 vite 支持这个组件测试的环境。
vue.config.js - 添加 test: { environment: 'jsdom' }
1 2 3 4 5 6 7 8 9 10 11 import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig ({ plugins : [vue ()], test : { environment : 'jsdom' , } })
2.3 测试 App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <template> <div> {{ count }} <button>add</button> </div> </template> <script setup> import { ref } from 'vue'; const count = ref(0) const add = () => { count++ } </script>
3.test.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { describe, test, expect } from 'vitest' import { fireEvent, render } from '@testing-library/vue' import Counter from './App.vue' describe ('测试 Counter 组件' , () => { test ('测试 Counter render' , async () => { const {getByText} = render (Counter ) getByText ("0" ) const button = getByText ("add" ) await fireEvent.click (button) getByText ("1" ) await fireEvent.click (button) getByText ("1" ) }) })]