[tools] Vitest
配置
預設不需要配置檔案也能運行,配置檔案執行優先度較高,有兩種配置檔案的撰寫方式
- 統一撰寫於
vite.config.js - 額外撰寫一個
vitest.config.js
//撰寫於 vite.config.js
export default {
test:{
//vitest 的配置撰寫位置
}
}
官方是推薦統一撰寫在
vite.config.js內,原因是 要維護兩邊文件因為 vitest 並不會繼承 vite 的配置內容,例如你在 vite 有設定 css 要如何被編譯,但在 vitest 並不會知道這個設定,在測試時可能會因為兩邊配置不同步而衍生的問題 。
下面是 vitest 主打的特色
- 預設支援 ESM
- HMR 功能,當你修改文件後會立刻更新
- 支援 Vue, React 等進行元件測試
- 支援 Typescript, JSX
- 快照測試、Mock 測試
- 包含 Jest 多數的功能
mode
預設是 watch mode ,當你變更文件時會立刻觸發改變
test API
it, test 比較
以 it , test 兩者進行測試結果上沒有差異,只是測試程式碼風格上的差別,自己的理解如下:
- 用
it撰寫在閱讀程式碼更有 情境 的感覺,可想像為it是主詞 test就是單純描述這個功能怎麼運作
舉例來說,今天要測試一個按鈕點擊後的功能
it('should become 3, when user clicks this button',()=>{
expect(wrapper.trigger('button')).toBe(3)
})
test('should become 3, when user clicks this button',()=>{
expect(wrapper.trigger('button')).toBe(3)
})
用 it 撰寫的測試,搭配 it Should 的命名風格,讀起來就有 它應該會 ... 語感,而用 test 撰寫的就比較單純是描述一個功能。
加入時間
default: 5000 ms
你可以在測試方法的第三個參數加入時間長度,也可以透過調整配置 testTimeout 修改預設值
test('test with time',()=>{
console.log('call test when time is out.')
},1000)
https://vitest.dev/config/#testtimeout
跳過特定測試
加入 skip() 可實現
- 單一測試情境跳過
- 系列測試情境跳過
//跳過單一測試
describe('many test',()=>{
//this test will be skiped
it.skip('',()=>{
})
})
//跳過整個系列測試
describe.skip('many test is skiped',()=>{
test('test1',()=>{})
test('test2',()=>{})
})
只執行單一測試
describe('many test is skiped',()=>{
//只執行這個測試
test.only('test1',()=>{})
//skip
test('test2',()=>{})
//skip
test('test3',()=>{})
})
測試失敗也會繼續進行
it("should failure, but test contiued",()=>{
const x = 1
expect.soft(x).toBe(3) // failure ,but test will be continued
expect(x).toBe(2) //failure
})
非同步行為同時觸發
使用 .concurrent() 讓兩個非同步行為同時觸發
import { describe, it } from 'vitest'
// All tests within this suite will be started in parallel
describe.concurrent('suite', () => {
it('concurrent test 1', async ({ expect }) => { /* ... */ })
it('concurrent test 2', async ({ expect }) => { /* ... */ })
it.concurrent('concurrent test 3', async ({ expect }) => { /* ... */ })
})
expect API
比較兩者是否相等
toBe
主要是比較 Primitive type 的變數值,或是同址物件
//primitive type
const a = 2
expect(a).toBe(2)
//reference type
const x = {name:1}
let y = x
expect(x).toBe(y)
請不要使用它測試浮點數相加,請改用 toBeCloseTo 進行測試。
test("two number plus",()=>{
expect(0.1+0.2).toBe(0.3) // error 0.300000000004
})
類似功能方法
expect(x).toBeNull() //equal .toBe(null)
expect(x).toBeNaN() // equal .toBe(NaN)
toEqual
與 toBe 功能類似,主要用於比較物件型別變數,這個方法只比較物件內架構,不比較記憶體指向,飲用官方文件範例,這個兩個相同架構的物件,分別使用 toBe , toEqual 測試是否相等。
import { expect, test } from 'vitest'
const stockBill = {
type: 'apples',
count: 13,
}
const stockMary = {
type: 'apples',
count: 13,
}
test('stocks have the same properties', () => {
expect(stockBill).toEqual(stockMary)
})
test('stocks are not the same', () => {
expect(stockBill).not.toBe(stockMary)
})
toStrictEqual
類似前者,差別在於
測試畫面元素
toMatchSnapShot
以快照方式檢查元素是否存在
1.toBeNull =>
比較變數型別
toBeTypeof
物件型別:[],{} ,new Map()
比較變數大小
toBeGreaterThan
toBeGreaterThanOrEqual
toBeLessThan
toBeLessThanOrEqual
測試函式是否有回傳值
toBeDefined
常用於確認函式是否有 undefined 以外的回傳值
function returnUndefined(){
console.log('123')
return 3
}
test("test function's return",()=>{
expect(returnUndefined()).toBeDefined()
})
字串內容
是否包含被測試的字串內容
descirbe API
mock
用來模擬非同步行為、回傳值
import {vi} from "vitest"
vi.fn().mockResolvedValue() //產生非同步操作回傳值
vi.fn().mockRejectedValue() //產生非同步操作失敗的回傳值
vitest 內建 vi 的韓式,建立模擬的函式
import {vi} from "vitest"
let mock = vi.fn()
設定 mock 函式回傳值
透過 mockReturnValue 設定
例如,你希望每次觸發 mock 函式都會回傳 42
import {vi} from "vitest"
let mock = vi.fn().mockReturnValue(42)
劫持模組內容
透過 vi.mock 自定義模組內行為及回傳值
當你引入特定模組功能,例如假設你今天引入 api 模組
import axios from "axios";
//創立一個axios的實例,統一提供app使用
const touristAPI = axios.create({
//baseURL:要一直被呼叫的API
baseURL: "https://ptx.transportdata.tw/MOTC/v2/Tourism/",
headers: {
Accept: "application/json",
},});
//它輸出的呼叫方法
export default {
getApidata:touristAPI.get('/path')
}
上述的 getApiData 方法呼叫是會真的發出請求的,然而單元測試的其中一個重要原則 隔絕依賴 ,因為真實發出請求會有幾個問題:
- 網路狀況影響
- 對資料庫產生副作用
- 測試應聚焦於行為驗證,而非依賴外部資源。
為了避免上述問題,透過 vi.mock 劫持並設定模組的行為與回傳值
import {vi,test} from "vitest"
import api from "/service/api"
//設定模組回傳值
vi.mock("/service/api",()=>{
//設定 getApiData 要回傳的內容
getApiData:vi.fn.mockReturnValue(42)
})
test("",async()=>{
const data = await api.getApiData()
expected(data).toBe(42)
})