AI Skill Library

Testing Strategy

Unit, integration, e2e -- when to use each; doubles, fixtures, naming.

testingquality
# Testing Strategy

## The pyramid
- **Unit** (many, fast, ms): pure functions, single module. No I/O.
- **Integration** (some, seconds): module + DB / HTTP / FS. Real boundaries with test infra.
- **End-to-end** (few, slow, minutes): full stack through UI/API.

## Naming
`describe('Cart')` / `it('applies discount when coupon valid')`
Pattern: `<unit>_<scenario>_<expected>` or BDD `Given/When/Then`.

## Arrange-Act-Assert
```ts
test('subtract', () => {
  // Arrange
  const a = 5, b = 2
  // Act
  const r = sub(a, b)
  // Assert
  expect(r).toBe(3)
})
```

## Test doubles
- **Stub**: returns canned data (no behavior verification).
- **Mock**: verifies interaction (`toHaveBeenCalledWith`).
- **Fake**: working light implementation (in-memory DB).
- **Spy**: wraps real impl + records calls.
Prefer fakes > stubs > mocks for resilience.

## Fixtures
- Build helpers, not raw data: `makeUser({ email: 'x' })`.
- Reset state between tests; use transactions for DB.

## What to test
- Public behavior, not implementation details.
- Boundary conditions, error paths.
- Don't test framework code or trivial getters.

## E2E (Playwright)
```ts
test('login', async ({ page }) => {
  await page.goto('/login')
  await page.getByLabel('Email').fill('a@b.c')
  await page.getByLabel('Password').fill('pw')
  await page.getByRole('button', { name: 'Sign in' }).click()
  await expect(page).toHaveURL('/dashboard')
})
```

API: /api/skills/testing-pyramid