testing

testing

熱門

Vitest 測試指南。適用於撰寫或更新測試、修復未通過的測試、提升測試覆蓋率、除錯測試問題或設定 Mock 模擬。

8.1萬星標
1.6萬分支
更新於 2026/8/7
SKILL.md
唯讀
名稱
testing
描述

Vitest 測試指南。適用於撰寫或更新測試、修復未通過的測試、提升測試覆蓋率、除錯測試問題或設定 Mock 模擬。

LobeHub 測試指南

快速參考

常用指令:

# 執行特定的測試檔案
bunx vitest run --silent='passed-only' '[file-path]'

# 資料庫套件(client-db,PGlite — 預設,跳過 BM25/pg_search)
cd packages/database && bunx vitest run --silent='passed-only' '[file]'

# 資料庫套件(server-db,Postgres — 對齊 BM25/pgvector,CI 測試覆蓋率採計標準)
cd packages/database && TEST_SERVER_DB=1 bunx vitest run --silent='passed-only' '[file]'

切勿執行 bun run test — 這會執行全部 3000 多個測試(約需 10 分鐘)。

資料庫 Model/Repository 規範: 凡是在 packages/database/src/models/**src/repositories/** 下新增的檔案,都必須在同一個 PR 中附帶同級的 __tests__/<name>.test.ts
請透過 getTestDB() 使用真實 DB(整合測試風格),使用 describe.skipIf(!isServerDB) 防護 BM25/全文檢索區塊,並務必測試使用者隔離(user-isolation)。環境設定、Schema 注意事項以及 client-vs-server-db 的差異,請參考 references/db-model-test.md

測試分類

類別 位置 設定檔
Webapp src/**/*.test.ts(x) vitest.config.ts
Packages packages/*/**/*.test.ts packages/*/vitest.config.ts
Desktop apps/desktop/**/*.test.ts apps/desktop/vitest.config.ts

核心原則

  1. 優先使用 vi.spyOn 而非 vi.mock — 目標更精確,也更易於維護
  2. 測試必須通過型別檢查 — 撰寫測試後請執行 bun run type-check
  3. 修復失敗 1~2 次後應即時停下尋求協助
  4. 測試外部行為,而非實作細節
  5. 修復 Bug 時需補上迴歸測試 — 修復 Bug 後,新增一個「修復前會失敗、修復後會通過」的迴歸測試,防止問題再次發生
  6. 不要新增 React 元件測試 — 僅維護現有的 React 元件測試。複雜邏輯應抽離至 Hooks 中進行獨立測試
  7. 先完成所有原始碼修改,再調整測試 — 先徹底完成原始碼修改,再統一更新測試。兩者交替進行會打亂對程式碼邏輯的思緒,特別是在跨多個檔案修改時

基本測試結構

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';

beforeEach(() => {
  vi.clearAllMocks();
});

afterEach(() => {
  vi.restoreAllMocks();
});

describe('ModuleName', () => {
  describe('functionName', () => {
    it('should handle normal case', () => {
      // Arrange → Act → Assert
    });
  });
});

Mock 模式

// ✅ 針對直接相依的模組進行 Spy
vi.spyOn(messageService, 'createMessage').mockResolvedValue('id');

// ✅ 使用 vi.stubGlobal 模擬瀏覽器 API
vi.stubGlobal('Image', mockImage);
vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock');

// ❌ 避免在全域 Mock 整個模組
vi.mock('@/services/chat'); // 範圍過大

詳細指南

具體測試情境請參閱 references/ 目錄:

  • 資料庫 Model 測試references/db-model-test.md
  • Electron IPC 測試references/electron-ipc-test.md
  • Zustand Store Action 測試references/zustand-store-action-test.md
  • Agent Runtime E2E 測試references/agent-runtime-e2e.md
  • Desktop Controller 測試references/desktop-controller-test.md

修復失敗的測試 — 優化還是刪除?

當測試因實作變更(而非 Bug)導致失敗時,盲目修復前請先進行評估:

保留並修復(更新測試資料/斷言)

  • 行為測試(Behavior tests):驗證程式碼「做了什麼」(輸出、副作用、使用者可見行為)的測試。只需更新 Mock 資料格式或預期結果值。
    • 範例:Tool 資料結構從 { name } 改為 { function: { name } } → 更新 Mock 資料
    • 範例:輸出格式從 Current date: YYYY-MM-DD 改為 Current date: YYYY-MM-DD (TZ) → 更新預期的字串

刪除(過度限定、價值低)

  • 參數轉發測試(Param-forwarding tests):斷言內部函式呼叫精確參數的測試(例如 expect(internalFn).toHaveBeenCalledWith(expect.objectContaining({ exact params })))——這類測試每次重構都會毀壞,且只是在重複行為測試已涵蓋的內容。
  • 與實作高度耦合的測試(Implementation-coupled tests):驗證程式碼內部「如何運作」而非「產生什麼結果」的測試。若較高層級的測試已涵蓋該行為,這類低層級測試只會增加維護成本,卻無法提高實質覆蓋率。

決策核對清單

  1. 測試是否驗證了外部可觀察的行為(API 回應、DB 寫入、渲染輸出)? → 保留
  2. 測試是否僅驗證內部呼叫流程(哪個函式接收了哪些參數)? → 檢查行為測試是否已涵蓋。若有 → 刪除
  3. 相同的行為是否已在更高的整合層級完成測試? → 刪除低層級的重複測試
  4. 測試是否會在下一次常規重構時再次損壞? → 考慮提升至整合層級測試或直接刪除

撰寫新測試時

  • 優先使用整合層級斷言(驗證最終輸出),而非白箱斷言(驗證內部呼叫)
  • 僅在面對穩定且公開的介面規格時使用 expect.objectContaining — 切勿用於隨重構頻繁變動的內部參數結構
  • 僅在系統邊界(DB、網路、外部服務)進行 Mock,不要在內部模組之間做 Mock

常見問題

  1. 模組污染(Module pollution):測試莫名失敗時,請使用 vi.resetModules()
  2. Mock 未生效:檢查設定位置,並在 beforeEach 中使用 vi.clearAllMocks()
  3. 測試資料污染:在 beforeEach/afterEach 中清理資料庫狀態
  4. 非同步問題(Async issues):針對 React Hooks 的狀態變更,請使用 act() 包裹