Test-Driven Development (TDD)

中级 Intermediate 纪律型 Discipline ⚡ Claude Code 专属 ⚡ Claude Code Optimized
4 min read · 178 lines

Red-Green-Refactor discipline — enforce tests-first methodology for AI-assisted coding

Test-Driven Development (TDD)

Overview

TDD enforces a strict "tests before code" methodology through the Red-Green-Refactor cycle. Write a failing test first (Red), implement minimal code to pass it (Green), then improve the code while keeping tests green (Refactor). Target: 80%+ test coverage.

Test Types

Type What to Test When
Unit Individual functions, components, pure logic Always
Integration API endpoints, database operations, service interactions Always
E2E Critical user flows via Playwright Critical paths

Edge Cases You Must Test

  1. Null/Undefined input
  2. Empty arrays/strings
  3. Invalid types
  4. Boundary values (min/max)
  5. Error paths (network failures, DB errors)
  6. Race conditions (concurrent operations)
  7. Large data (10k+ items)
  8. Special characters (Unicode, emojis, SQL chars)

Testing Patterns

Unit Test (Jest/Vitest)

describe('Button Component', () => {
  it('renders with correct text', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByText('Click me')).toBeInTheDocument()
  })

  it('calls onClick when clicked', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click</Button>)
    fireEvent.click(screen.getByRole('button'))
    expect(handleClick).toHaveBeenCalledTimes(1)
  })
})

API Integration Test

describe('GET /api/markets', () => {
  it('returns markets successfully', async () => {
    const request = new NextRequest('http://localhost/api/markets')
    const response = await GET(request)
    const data = await response.json()
    expect(response.status).toBe(200)
    expect(data.success).toBe(true)
  })

  it('validates query parameters', async () => {
    const request = new NextRequest('http://localhost/api/markets?limit=invalid')
    const response = await GET(request)
    expect(response.status).toBe(400)
  })
})

E2E Test (Playwright)

test('user can search and filter markets', async ({ page }) => {
  await page.goto('/')
  await page.click('a[href="/markets"]')
  await page.fill('input[placeholder="Search markets"]', 'election')
  await page.waitForTimeout(600)
  const results = page.locator('[data-testid="market-card"]')
  await expect(results).toHaveCount(5, { timeout: 5000 })
})

Mocking External Services

// Supabase
jest.mock('@/lib/supabase', () => ({
  supabase: {
    from: jest.fn(() => ({
      select: jest.fn(() => ({
        eq: jest.fn(() => Promise.resolve({ data: [...], error: null }))
      }))
    }))
  }
}))

// Redis
jest.mock('@/lib/redis', () => ({
  searchMarketsByVector: jest.fn(() => Promise.resolve([...])),
  checkRedisHealth: jest.fn(() => Promise.resolve({ connected: true }))
}))

Anti-Patterns to Avoid

Anti-Pattern Correct Approach
Testing implementation details (internal state) Test user-visible behavior
Brittle CSS selectors Use semantic selectors or data-testid
Tests depending on each other (shared state) Independent tests with own setup
Asserting too little Specific, meaningful assertions
Writing implementation before tests Always write tests first

Coverage Requirements

  • 80% minimum for all code (branches, functions, lines, statements)
  • 100% required for: financial calculations, authentication, security-critical code, core business logic

Best Practices

  1. Write the test FIRST, before any implementation
  2. One assert per test — focus on single behavior
  3. Use Arrange-Act-Assert structure
  4. Mock external dependencies to isolate units
  5. Keep tests fast (unit tests < 50ms each)
  6. Clean up after tests — no side effects
  7. Use watch mode during development: npm test -- --watch

Integration with Other Commands

Command Purpose
/plan Understand what to build
/tdd Implement with tests
/build-fix Fix build errors
/code-review Review implementation
/test-coverage Verify coverage

Remember: Tests are not optional. They are the safety net that enables confident refactoring, rapid development, and production reliability.

相关技能 Related Skills