测试工具
vitest
测试实例
import { type VueWrapper, mount } from '@vue/test-utils'
import {afterAll, beforeAll, describe, expect, test } from 'vitest'
import operateBar from '../../operateBar.vue'
import type { ComponentPublicInstance } from 'vue'
describe('模块名', () => {
let wrapper: VueWrapper<ComponentPublicInstance>
beforeAll(() => {
wrapper = mount(operateBar, {
props: {},
emits: {},
global: {
components: {
'el-input': ElInput // 全局注册组件
},
plugins: [VueI18n], // app.use(vue-i18n)
directives: {},
}
})
})
afterAll(() => {
wrapper && wrapper.unmount()
})
test('测试用例1', async () => {
wrapper.exists() // 是否存在
wrapper.vm // 组件实例
wrapper.vm.$emit('foo') // 抛出组件上的事件
wrapper.vm.xxx() // 执行组件上的方法
element.trigger('click') // 点击
wrapper.emitted().action.toBeTruthy()
wrapper.emitted().foo // 返回一个数组,返回的数组中每一项是执行一次 emit 的返回结果,如返回:[['abc'], ['def']],这是执行了2次 emit 的结果
wrapper.emitted().action // .toEqual([['copy']])
const header = wrapper.findComponent(Header) // 从 wrapper 中查找子组件 Header
const element = wrapper.find('.xxx') // 获取元素
const element = wrapper.findAll('[data-test="xxx"]').at(0) // 获取元素
expect(element).toBe(xxx)
expect(element).toEqual(xxx) // 可以对比数组
expect(element).toMatch(msg)
expect(element).toBeFalsy()
expect(element).toBeTruthy() // 是否为 true
})
})
JEST
异步函数的测试
回调形式的异步函数
使用 done() 函数,done调用之前不会结束测试
test('回调测试异步', (done) => {
fetchData(res => {
expect(res.data.data.a).toBe(2)
done()
})
})
Promise 形式的异步函数
test(' promise 测试异步', () => {
return fetchData().then(res => {
expect(res.data.data.a).toBe(2)
})
})
对于 catch 的捕获测试,需要借助 expect.asertions() 函数,参数表示执行几次 expect 之后结束:
test(' catch 测试异步', () => {
expect.asertions(1)
return fetchData().catch(e => {
expect(e.toString().includes('404')).toBe(true)
})
})
其他异步测试的方法
// async await 代替 return
test('其他异步测试方法', async () => {
await expect(fetchData()).resoves.toMatchObject({
data: { code: 0 }
})
})
test('其他异步测试方法', async() => {
await expect(fetchData()).rejects.toThrow()
})
Jest 中的钩子函数
beforeAll() // 所有用例执行之前初始化
beforeAll(() => {
counter = new Counter();
})
afterAll() // 所有用例执行之后
beforeEach() // 每一个用例执行之前
afterEach() // 每一个用例执行之后
单个用例调试
test.only('', () => {})
Mock
mock 一个函数,可以捕获函数的调用
const func = jest.fn() // 生成函数
runCallback(func) // 执行
runCallback(func)
expect(func).toBeCalled()
// expect(func.mock.results.length).toBe(2)
// func.mock.calls -> func函数被调用时接收的参数
// func.mock.result -> func函数被调用时返回值描述
对于 axios 异步请求的测试,mock 发送请求
import axios from 'axios';
jest.mock('axios');
test('测试 axios', async () => {
axios.get.mockResolvedValue({data: 'hello'})
await axios.get('/api').then((res) => {
expect(res.data).toBe('hello')
})
})
snapshot 测试快照
快照可以防止配置文件误修改;
test('测试配置数据', () => {
expect(configJson).toMatchSnapshot({
time: expect.any(Date), // time 是 Date 类型的数据即可
name: expect.any(String)
});
})
修改配置文件了之后按 u 更新快照;
对于UI组件的单元测试也比较适用;
mock 进阶 - 异步请求修改为本地 Promise
真正的业务代码:
import axios from 'axios'
export const fetchData = () => {
return axios.get('/api')
}
方案一 mock 方法
mock: 同级创建 __mocks__
文件夹,里面创建同名文件
export const fetchData = () => {
return new Promise((resolve, reject) => {
resolve({
status: 200,
data: 'xxxx'
})
})
}
测试代码 (模拟的是 featchData 这个函数):
import { fetchData } from './api.js'
jest.mock('./api.js')
test('fetchData test', () => {
return fetchData().then(res => {
expect(res.data).toBe('xxxx')
})
})
方案二 mock axios
测试代码 (模拟的是 axios 返回值):
import Axios from 'axios'
import { fetchData } from './api.js'
jest.mock('axios')
test('fetchData test', () => {
Axios.get.mockResolvedValue({
code: 200,
data: 'xxxx'
})
return fetchData().then(res => {
expect(res.data).toBe('xxxx')
})
})
mock timers 定时器测试
import timer from './timer.js'
// 为了解决多个用例对 timer 的影响
beforeEach(() => {
jest.useFakeTimers() // 使用模拟的 timer,相当于初始化
})
test('测试定时器', () => {
const fn = jest.fn()
timer(fn)
jest.runAllTimers() // 立即执行所有定时器
expect(fn).toHaveBeenCalledTimes(1) // 定时器被调用了几次
})
// jest.advancedTimersByTime(3000) 快进3秒
// jest.runOnlyPendingTimers() 仅运行当前队列中的 timer
包含 class 类的方法的测试
原理:模拟一个类,去执行模拟的类的方法。
// 如果util是类,会自动重写util中的方法为jest.fn
import demoFun from './demo'
import Util from './util' jest.mock('./util')
// Util => jest.fn()
// Util.a => jest.fn()
// Util.b => jest.fn()
test('测试 class', () => {
demoFun()
expect(Util).toHaveBeenCalled()
expect(Util.mock.instances[0].a).toHaveBeenCalled() // 找实例
expect(Util.mock.instances[0].b).toHaveBeenCalled()
})