Testing 每次測試這一塊都是內心想花點時間實作
最後都沒時間認真實作www
測試還是蠻重要的吧 哈
自動化測試能幫助您和您的團隊快速且自信地構建複雜的 Vue 應用,透過防止回歸並鼓勵您將應用拆分為可測試的函數、模組、類別和組件。與所有應用一樣,新的 Vue 應用可能會以多種方式出錯,因此在發布前能發現並修復這些問題是很重要的。
在本指南中,我們將介紹基本術語,並提供我們推薦的 Vue 3 應用測試工具。此外,指南包含針對 Vue 特定的可組合項目測試的部分,詳情請參考下方的「測試可組合項目」部分。
越早開始測試越好!我們建議您儘早編寫測試。拖得越久,應用的相依性就越多,開始測試的難度也會越高。
設計 Vue 應用的測試策略時,您應考慮以下測試類型:
每種測試類型在應用的測試策略中都發揮著作用,並能防範不同類型的問題。
我們將簡要討論每種類型的測試是什麼、如何在 Vue 應用中實現它們,並提供一些一般建議。
單元測試用來驗證小而獨立的代碼單元運行是否符合預期。通常測試一個函數、類別、可組合的功能或模組,關注邏輯正確性,只涵蓋應用的一小部分功能,可能模擬應用的環境(如初始狀態、複雜類別、第三方模組和網絡請求)。
一般來說,單元測試可以捕捉到函數業務邏輯和邏輯正確性的問題。
例如此增量函數:
// helpers.js
export function increment (current, max = 10) {
if (current < max) {
return current + 1;
}
return current;
}
這個函數是獨立的,很容易進行測試,確保返回預期結果。
// helpers.spec.js
import { increment } from './helpers';
describe('increment', () => {
test('increments the current number by 1', () => {
expect(increment(0, 10)).toBe(1);
});
test('does not increment the current number over the max', () => {
expect(increment(10, 10)).toBe(10);
});
test('has a default max of 10', () => {
expect(increment(10)).toBe(10);
});
});
單元測試通常針對不涉及 UI 渲染、網絡請求或環境的業務邏輯。
Vue 應用中有兩個 Vue 特定的單元測試場景:
Vue 應用中特有的可組合功能可能需要特殊測試處理,詳見「測試可組合功能」。
組件測試有兩種方式:
以下組件測試建議如下:
由於 Vue 官方使用 Vite 建立配置,建議使用 Vitest 進行單元測試。Vitest 由 Vue / Vite 團隊開發,與 Vite 集成簡便且速度快。
Jest 是常見的單元測試框架,但僅當已有 Jest 測試集需遷移至 Vite 時使用,否則建議使用 Vitest 以獲得更佳的效能和整合。
在 Vue 應用中,組件是 UI 的主要構建塊,因此它們成為驗證應用行為時自然的隔離單元。從粒度上來看,組件測試位於單元測試之上,可視為一種整合測試。大部分 Vue 應用應覆蓋組件測試,建議為每個 Vue 組件編寫專屬的測試文件。
組件測試應捕捉與組件屬性、事件、插槽、樣式、類別、生命週期勾子等相關的問題。組件測試不應模擬子組件,而應透過用戶互動方式測試組件與子組件間的交互。例如,測試中應透過點擊元素來操作組件,而不是直接程式化操作。
組件測試應關注組件的公開介面,而非內部實現細節。對於大多數組件,公開介面僅限於:發出的事件、屬性與插槽。測試時應著重於組件的行為,而非其實現。
以下範例展示了 Stepper 組件,其包含一個標示為 "increment" 的 DOM 元素,且可以點擊。我們傳遞一個 max
屬性,防止 Stepper 增加到超過 2,所以點擊 3 次後,UI 仍應顯示 2。
const valueSelector = '[data-testid=stepper-value]'
const buttonSelector = '[data-testid=increment]'
const wrapper = mount(Stepper, {
props: {
max: 1
}
})
expect(wrapper.find(valueSelector).text()).toContain('0')
await wrapper.find(buttonSelector).trigger('click')
expect(wrapper.find(valueSelector).text()).toContain('1')
useFavicon
)。可用 @vue/test-utils
測試組件和 DOM。@testing-library/cypress
。Vitest 與基於瀏覽器的測試執行器之間的主要差異在於速度與執行環境。簡而言之,像 Cypress 這樣的瀏覽器執行器可以發現一些 Node.js 執行器(如 Vitest)無法檢測的問題(例如樣式問題、真實的原生 DOM 事件、Cookies、本地儲存和網絡故障)。然而,瀏覽器執行器的速度比 Vitest 慢很多,因為它需要開啟瀏覽器、編譯樣式等。Cypress 是一款支援組件測試的瀏覽器執行器。請參考 Vitest 的比較頁面以獲取 Vitest 與 Cypress 最新的比較資訊。
組件測試通常涉及單獨掛載組件、模擬用戶事件並驗證 DOM 輸出,有專門工具庫可簡化這些任務。
@testing-library/vue
底層基於此庫。我們建議在應用程式中使用 @vue/test-utils 來測試組件。@testing-library/vue 在測試具有 Suspense 的非同步組件時存在一些問題,因此應謹慎使用。
雖然單元測試能提供一定的信心,但單元和組件測試無法全面涵蓋應用在生產環境中運行時的情況。因此,端到端(E2E)測試提供了更全面的覆蓋範圍,專注於應用實際運行時的行為。
E2E 測試的重點在於多頁面應用的行為,它會針對已部署的 Vue 應用進行網路請求。通常需要連接資料庫或其他後端服務,甚至可能在測試環境中執行。
E2E 測試通常可以檢測到路由、狀態管理、頂層組件(例如 App 或 Layout)、公共資源或請求處理上的問題。它不會匯入任何 Vue 應用程式的程式碼,而是透過瀏覽器模擬實際操作應用的情況。
E2E 測試涵蓋應用的多層面。可以在本地或線上測試環境中測試,這樣不僅涵蓋前端和靜態伺服器,還涵蓋後端服務和基礎設施。
Kent C. Dodds 說道:「測試越貼近真實使用情況,能提供的信心就越高。」
E2E 測試透過模擬使用者行為提升信心,確保應用正常運行。
雖然 E2E 測試曾因不穩定而惡名昭彰,但現代工具已經改善了這一問題。選擇 E2E 測試框架時,請考慮以下幾點。
E2E 測試的主要優勢是能跨多個瀏覽器測試應用,但 100% 覆蓋的效益可能隨資源投入而遞減。選擇適合的跨瀏覽器測試程度有助於資源最佳化。
E2E 測試執行時間長,通常僅在 CI/CD 中完整執行。現代 E2E 框架支援平行執行來提升速度,並支援單獨測試和測試熱重新加載,提升開發效率。
傳統上需查看終端日誌來排錯,現代框架則允許使用瀏覽器開發工具,提升除錯便利性。
在 CI/CD 管線中,E2E 測試常使用無頭瀏覽器執行。現代 E2E 框架提供截圖或錄影功能,有助於識別錯誤原因。
Playwright:支援 Chromium、WebKit 和 Firefox,能在 Windows、Linux 和 macOS 執行。擁有出色的 UI、除錯功能、內建斷言、平行執行和防止不穩定測試的設計。支援組件測試(實驗性)。
Cypress:具備豐富的圖形介面、出色的除錯功能、內建斷言、快照等。支援 Chromium、Firefox 和 Electron。WebKit 支援為實驗性,部分平行化功能需 Cypress Cloud 訂閱。
Nightwatch:基於 Selenium WebDriver,支援最多瀏覽器。
WebdriverIO:基於 WebDriver 協議,適用於網頁和行動裝置的測試框架。
在基於 Vite 的 Vue 專案中,運行以下命令:
> npm install -D vitest happy-dom @testing-library/vue
接下來,更新 Vite 配置以添加測試選項區塊:
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
// ...
test: {
// 啟用類似 Jest 的全域測試 API
globals: true,
// 使用 happy-dom 模擬 DOM
// (需要將 happy-dom 安裝為 peer 依賴)
environment: 'happy-dom'
}
})
提示:如果您使用 TypeScript,請在tsconfig.json
的types
欄位中添加vitest/globals
。
// tsconfig.json
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
然後,在您的專案中創建一個以 .test.js
結尾的檔案。您可以將所有測試檔案放在專案根目錄的 test
目錄中,或放在與源檔案相鄰的 test
目錄中。Vitest 將自動使用命名慣例搜尋它們。
// MyComponent.test.js
import { render } from '@testing-library/vue'
import MyComponent from './MyComponent.vue'
test('it should work', () => {
const { getByText } = render(MyComponent, {
props: {
/* ... */
}
})
// 驗證輸出
getByText('...')
})
最後,更新 package.json
以添加測試腳本並運行它:
{
// ...
"scripts": {
"test": "vitest"
}
}
> npm test
本節假設您已閱讀過可組合函式的相關內容。
在測試可組合函式時,可以將其分為兩類:不依賴於宿主組件實例的可組合函式,以及依賴於宿主組件實例的可組合函式。
當可組合函式使用以下 API 時,則依賴於宿主組件實例:
如果可組合函式僅使用響應式 API,那麼可以直接調用它並驗證其返回的狀態/方法:
// counter.js
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
const increment = () => count.value++
return {
count,
increment
}
}
// counter.test.js
import { useCounter } from './counter.js'
test('useCounter', () => {
const { count, increment } = useCounter()
expect(count.value).toBe(0)
increment()
expect(count.value).toBe(1)
})
依賴於生命週期鉤子或提供 / 注入的可組合函式需要包裹在宿主組件中進行測試。我們可以創建一個幫助函式,如下所示:
// test-utils.js
import { createApp } from 'vue'
export function withSetup(composable) {
let result
const app = createApp({
setup() {
result = composable()
// 抑制缺少模板的警告
return () => {}
}
})
app.mount(document.createElement('div'))
// 返回結果和應用實例
// 以便測試提供/卸載
return [result, app]
}
import { withSetup } from './test-utils'
import { useFoo } from './foo'
test('useFoo', () => {
const [result, app] = withSetup(() => useFoo(123))
// 模擬提供以測試注入
app.provide(...)
// 執行斷言
expect(result.foo.value).toBe(1)
// 如果需要,觸發 onUnmounted 鉤子
app.unmount()
})
對於更複雜的可組合函式,通過使用組件測試技術編寫測試包裝組件也可能更容易進行測試。
測試的章節比我想像中的還多資訊@@
真的要實作過會比較有印象....Orz...
繼續堆疊知識中...www