Rigorous Testing Protocol
1. 黃金法則
「如果沒測試,就不算完成。」
- •永遠不要假設修改有效而不跑測試
- •如果現有測試失敗,修復代碼而非修改測試(除非測試本身過時)
- •每個 bug 修復必須有回歸測試
2. 測試時機
修改前(建立基準)
bash
# 跑相關測試檔案,確認當前狀態 npm run test <相關檔案>
開發中(TDD 循環)
code
RED → 先寫失敗的測試 GREEN → 寫最少代碼讓測試通過 REFACTOR → 優化代碼,保持測試通過
修改後(確保無回歸)
bash
# 跑完整測試套件 npm test
3. MaiHouses 測試堆疊
單元測試 (Vitest)
- •用途: 工具函數、hooks、獨立組件
- •Mock: 使用
vi.mock模擬 API - •路徑:
src/**/__tests__/*.test.ts
typescript
// 範例
import { describe, it, expect, vi } from "vitest";
describe("功能名稱", () => {
it("應該正確處理某情況", () => {
// Arrange
const input = "test";
// Act
const result = myFunction(input);
// Assert
expect(result).toBe("expected");
});
});
整合測試 (API)
- •用途: Backend 邏輯 (
api/目錄) - •Mock: 使用
node-mocks-http模擬 Request/Response - •路徑:
api/**/__tests__/*.test.ts
E2E 測試 (Playwright)
- •用途: 關鍵用戶流程(登入、發文等)
- •路徑:
tests/e2e/*.spec.ts
4. 必做檢查清單
每次修改後
- • 跑過相關測試檔案?
- • 所有測試通過?
- • 如果修復 bug,有新增回歸測試?
- • TypeScript 類型檢查通過? (
npm run typecheck)
提交前
- • 完整測試套件通過? (
npm test) - • 無跳過的測試?
- • 測試覆蓋新增的代碼?
5. 測試命名規範
typescript
describe("模組/組件名稱", () => {
describe("功能分類", () => {
it("應該 [預期行為] 當 [條件]", () => {
// ...
});
});
});
// 範例
describe("useComments", () => {
describe("toggleLike", () => {
it("應該正確切換按讚狀態當用戶點擊", () => {
// ...
});
it("應該回滾狀態當 API 失敗", () => {
// ...
});
});
});
6. 常見測試模式
Mock API 呼叫
typescript
vi.mock("../lib/supabase", () => ({
supabase: {
from: vi.fn(() => ({
select: vi.fn(() => ({
eq: vi.fn(() => Promise.resolve({ data: [], error: null })),
})),
})),
},
}));
Mock Hook
typescript
vi.mock("../hooks/useAuth", () => ({
useAuth: () => ({
user: { id: "test-user" },
isLoggedIn: true,
}),
}));
測試異步操作
typescript
it("應該處理異步操作", async () => {
const { result } = renderHook(() => useMyHook());
await act(async () => {
await result.current.asyncAction();
});
expect(result.current.state).toBe("expected");
});
測試錯誤情況
typescript
it("應該正確處理錯誤", async () => {
// Mock API 返回錯誤
vi.mocked(fetch).mockRejectedValueOnce(new Error("Network error"));
const { result } = renderHook(() => useMyHook());
await act(async () => {
await result.current.action();
});
expect(result.current.error).toBe("Network error");
});
7. 故障排除
測試掛起
- •檢查未關閉的 handles 或 DB 連線
- •確認所有 Promise 都有 await
測試不穩定 (Flaky)
- •檢查 async/await 問題
- •檢查共享狀態
- •使用
waitFor等待異步更新
Mock 不生效
- •確認 mock 在 import 之前
- •檢查 mock 路徑是否正確
- •使用
vi.clearAllMocks()在beforeEach
8. 測試指令速查
bash
# 執行所有測試 npm test # 執行單一檔案 npx vitest run src/path/to/file.test.ts # 監視模式 npm run test:watch # 查看覆蓋率 npx vitest run --coverage # 只跑符合名稱的測試 npx vitest run -t "測試名稱關鍵字"
9. 與其他 Skills 整合
| 階段 | 整合 Skill | 說明 |
|---|---|---|
| 測試前 | /read-before-edit | 先讀懂現有測試 |
| 寫測試 | /code-validator | 確保測試代碼品質 |
| 測試失敗 | /type-checker | 修復類型問題 |
| 提交前 | /pre-commit-validator | 確保所有測試通過 |
10. 記住
code
┌─────────────────────────────────────────────────────────────────┐ │ │ │ 🧪 沒有測試的代碼 = 不存在的代碼 │ │ │ │ ✅ 測試通過 ≠ 代碼正確(但至少有基本保障) │ │ │ │ 🔄 測試失敗 → 修復代碼,不是刪除測試 │ │ │ └─────────────────────────────────────────────────────────────────┘