27
Re:Nuxt 100 天練習曲
Day 27

檢查零件的好壞 (單元測試)

Day 27·元件測試·隔離測試

單元測試的核心思想是「隔離」。

當我們測試一個方向盤時,我們只關心方向盤本身轉動順不順,不關心它連接著哪個輪胎或車身。在 Nuxt 中,這意味著我們會把一個元件從整個應用程式中抽離出來,單獨測試它的行為是否符合預期。

1. 我們的測試主角:mountSuspended

要測試一個元件,我們得先把它「渲染」出來。@nuxt/test-utils 為此提供了一個關鍵函式 mountSuspended

它會在一個模擬的 Nuxt 環境中,安全地掛載(mount)您的元件。即使元件的 setup 中有非同步的行為(例如 await useFetch()),它也能妥善處理,確保元件被完整渲染後才開始測試。

mountSuspended 的特色
  • • 在模擬的 Nuxt 環境中安全掛載元件
  • • 能處理非同步的 setup 邏輯
  • • 支援 Nuxt 的 auto-imports 功能
  • • 確保元件完整渲染後才開始測試

2. 第一次元件測試實戰

讓我們來測試一個簡單的歡迎元件。

1

第一步:建立要被測試的元件

components/ 資料夾中建立一個 Welcome.vue

components/Welcome.vue
<template>
  <div>
    <h1>歡迎來到我的網站!</h1>
  </div>
</template>
2

第二步:建立測試檔案

在專案根目錄建立 tests/components/ 資料夾,並在裡面建立 Welcome.nuxt.spec.ts

檔名慣例

  • tests/ 是約定俗成的測試檔案放置處
  • .spec.ts.test.ts 是測試檔案的常見後綴
  • 檔名中的 .nuxt. 是在告訴 Vitest:「請在模擬的 Nuxt 環境中執行這個測試!」
3

第三步:撰寫測試程式碼

tests/components/Welcome.nuxt.spec.ts
// tests/components/Welcome.nuxt.spec.ts

// 從 vitest 引入測試的核心函式
import { describe, test, expect } from 'vitest';
// 從 @nuxt/test-utils 引入掛載工具
import { mountSuspended } from '@nuxt/test-utils/runtime';
// 引入我們要測試的元件
import Welcome from '~/components/Welcome.vue';

// 'describe' 用來群組相關的測試案例
describe('Welcome 元件', () => {

  // 'test' 或 'it' 代表一個獨立的測試案例
  test('應該要能正確渲染歡迎訊息', async () => {
    
    // 1. 掛載元件
    const wrapper = await mountSuspended(Welcome);

    // 2. 進行「斷言 (Assertion)」
    //    我們「期望」元件渲染出來的文字內容,「包含」'歡迎來到我的網站!' 這段文字
    expect(wrapper.text()).toContain('歡迎來到我的網站!');
  });
});

斷言概念expect(...) 就是「斷言」,意思是我們對測試結果的「期望」。如果實際結果符合期望,測試就通過;反之則失敗。

執行測試:現在,您可以在終端機執行 npm run test (或 yarn test),看看測試通過的訊息!

3. 進階觀念:關於「模擬 (Mocking)」

單元測試強調「隔離」。如果 Welcome 元件需要呼叫 useUser() 來取得使用者名稱,在測試時,我們不希望它真的去執行 useUser() 的邏輯,而是希望直接給它一個假的使用者名稱。這個「假裝」的過程,就叫做模擬 (Mocking)。

為什麼需要模擬?

  • 隔離測試:只測試目標元件,不受其他元件或 API 影響
  • 可控制性:可以模擬各種情況,包括錯誤狀態
  • 測試速度:避免真實的網路請求,讓測試更快
  • 可重複性:確保每次測試都有相同的條件

@nuxt/test-utils 提供的模擬工具

mockNuxtImport
模擬 Nuxt 的 composables
mockComponent
模擬子元件

簡單模擬範例

// 模擬 useUser composable
mockNuxtImport('useUser', () => {
  return () => ({
    name: '測試用戶',
    email: 'test@example.com'
  })
})

未來實戰:這些模擬工具在未來的實戰中會非常有用,能讓我們精確控制測試環境。

測試最佳實踐

好的測試應該

測試行為而非實作細節

有清楚的測試名稱

獨立且可重複執行

執行速度要快

涵蓋邊界情況

避免的陷阱

測試實作細節而非功能

測試之間有相依性

過度複雜的測試設定

忽略錯誤情況的測試

模糊不清的測試名稱

今日總結

今天我們學會了單元測試的核心流程:掛載元件 (mountSuspended),然後進行斷言 (expect)。透過這個模式,您可以確保您開發的每一個小元件都如預期般運作。

隔離測試的核心概念

單獨測試元件功能,不受外部相依性影響

掌握 mountSuspended 和斷言

學會在 Nuxt 環境中掛載元件並驗證其行為

了解模擬(Mocking)的重要性

為進階測試場景打下基礎,控制測試環境

下一步預告

檢查完單一零件後,下一步當然就是把整台車組裝起來上路實測了!明天,我們將學習端到端 (E2E) 測試,模擬真實使用者操作我們的網站。