Skip to main content

tdd

TDD (Test-Driven Development) 最佳實踐指南,搭配 Vitest + React Testing Library。當需要撰寫測試、實踐 Red-Green-Refactor、設計測試結構時使用。應在開發新功能時主動套用。

Aller à l'installation

Informations de source

Dépôt
recca0120/rubik-cube
Dernière activité de la source
14 avril 2026 à 20:53
Langue détectée de SKILL.md
chinois
Étoiles
1
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
tdd
description
TDD (Test-Driven Development) 最佳實踐指南,搭配 Vitest + React Testing Library。當需要撰寫測試、實踐 Red-Green-Refactor、設計測試結構時使用。應在開發新功能時主動套用。
# TDD 最佳實踐(Vitest + RTL) ## Red-Green-Refactor 1. **Red**:先寫一個失敗的測試(描述想要的行為) 2. **Green**:用最小修改讓測試過(允許醜陋) 3. **Refactor**:保持綠燈重構 **鐵律**: - 每次只讓一個測試紅 → 綠 - 不寫沒對應測試的生產代碼 - 不重構沒綠燈的代碼 - 小步前進:每 2-5 分鐘一次紅綠循環 ## 安裝 ```bash pnpm add -D vitest @vitest/ui jsdom \ @testing-library/react @testing-library/user-event \ @testing-library/jest-dom ``` ## vite.config.ts ```ts /// <reference types="vitest" /> import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], test: { globals: true, environment: 'jsdom', setupFiles: './src/test/setup.ts', coverage: { reporter: ['text', 'html'] }, }, }) ``` `src/test/setup.ts`: ```ts import '@testing-library/jest-dom/vitest' import { cleanup } from '@testing-library/react' import { afterEach } from 'vitest' afterEach(() => cleanup()) ``` ## 檔案命名 - `foo.ts` → `foo.test.ts` 同資料夾 - 或 `__tests__/foo.test.ts` - 選一種專案內一致 ## 測試結構(AAA) ```ts import { describe, it, expect, beforeEach, vi } from 'vitest' describe('Cube', () => { let cube: Cube beforeEach(() => { cube = new Cube() }) it('rotates U face clockwise', () => { // Arrange cube.apply('U') // Act const top = cube.getFace('U') // Assert expect(top).toEqual(Array(9).fill('U')) }) }) ``` ## React Testing Library ```tsx import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' it('increments on click', async () => { const user = userEvent.setup() render(<Counter />) await user.click(screen.getByRole('button', { name: /add/i })) expect(screen.getByText('1')).toBeInTheDocument() }) ``` **Query 優先順序**:`getByRole` > `getByLabelText` > `getByPlaceholderText` > `getByText` > `getByTestId`(最後手段)。 ## 測試金字塔 ``` E2E (Playwright) ← 少量、關鍵流程 Integration (RTL) ← 元件 + store Unit (Vitest pure functions) ← 大量、邏輯 ``` **本專案分層建議**: - **純邏輯**(cube state、solver wrapper、color classify)→ 大量 unit test - **React 元件**(Input 表單、教學面板)→ RTL integration test - **3D 元件**(R3F scene)→ 不測渲染,測背後的 state/邏輯 ## 該測什麼 ✅ **測行為**:給定輸入 → 期待輸出/副作用 ✅ 邊界條件、錯誤處理、public API ❌ **不測實作細節**:私有函式、內部 state 欄位 ❌ 不測第三方套件本身 ❌ 不測 trivial getter/setter ## Mock 策略 見 `test-doubles` skill。原則:**能不 mock 就不 mock**,優先 Fake > Stub > Mock。 ## 魔術方塊範例(TDD walkthrough) ```ts // 1. Red it('U move rotates top face clockwise', () => { const cube = new Cube() cube.apply('U') expect(cube.facelets.slice(0, 9)).toBe('UUUUUUUUU') expect(cube.facelets.slice(9, 12)).toBe('FFF') // R top row = F }) // 2. Green (最小實作) class Cube { facelets = 'UUUUUUUUU RRR... ' apply(move: string) { if (move === 'U') { /* 實作 U */ } } } // 3. Refactor:抽 rotateFace 工具、查表驅動 6 面 ``` ## 檢查清單 - [ ] 每次改代碼前先看看有沒有測試覆蓋 - [ ] 一個測試只驗一件事 - [ ] 測試名稱講「做什麼」不是「怎麼做」 - [ ] `pnpm test` 全綠才 commit - [ ] coverage 看趨勢不看絕對值
Voir sur GitHub