skills/cityfish91159/maihouses/rigorous_testing

rigorous_testing

SKILL.md

Rigorous Testing Protocol

1. 黃金法則

「如果沒測試,就不算完成。」

  • 永遠不要假設修改有效而不跑測試
  • 如果現有測試失敗,修復代碼而非修改測試(除非測試本身過時)
  • 每個 bug 修復必須有回歸測試

2. 測試時機

修改前(建立基準)

# 跑相關測試檔案,確認當前狀態
npm run test <相關檔案>

開發中(TDD 循環)

RED    → 先寫失敗的測試
GREEN  → 寫最少代碼讓測試通過
REFACTOR → 優化代碼,保持測試通過

修改後(確保無回歸)

# 跑完整測試套件
npm test

3. MaiHouses 測試堆疊

單元測試 (Vitest)

  • 用途: 工具函數、hooks、獨立組件
  • Mock: 使用 vi.mock 模擬 API
  • 路徑: src/**/__tests__/*.test.ts
// 範例
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. 測試命名規範

describe("模組/組件名稱", () => {
  describe("功能分類", () => {
    it("應該 [預期行為] 當 [條件]", () => {
      // ...
    });
  });
});

// 範例
describe("useComments", () => {
  describe("toggleLike", () => {
    it("應該正確切換按讚狀態當用戶點擊", () => {
      // ...
    });

    it("應該回滾狀態當 API 失敗", () => {
      // ...
    });
  });
});

6. 常見測試模式

Mock API 呼叫

vi.mock("../lib/supabase", () => ({
  supabase: {
    from: vi.fn(() => ({
      select: vi.fn(() => ({
        eq: vi.fn(() => Promise.resolve({ data: [], error: null })),
      })),
    })),
  },
}));

Mock Hook

vi.mock("../hooks/useAuth", () => ({
  useAuth: () => ({
    user: { id: "test-user" },
    isLoggedIn: true,
  }),
}));

測試異步操作

it("應該處理異步操作", async () => {
  const { result } = renderHook(() => useMyHook());

  await act(async () => {
    await result.current.asyncAction();
  });

  expect(result.current.state).toBe("expected");
});

測試錯誤情況

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. 測試指令速查

# 執行所有測試
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. 記住

┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│   🧪 沒有測試的代碼 = 不存在的代碼                              │
│                                                                 │
│   ✅ 測試通過 ≠ 代碼正確(但至少有基本保障)                    │
│                                                                 │
│   🔄 測試失敗 → 修復代碼,不是刪除測試                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
Weekly Installs
3
First Seen
1 day ago
Installed on
opencode3
codex3
claude-code3
antigravity3
gemini-cli3
windsurf2