# Testing

> Testing patterns — Playwright E2E, test structure, fixture management, mock boundaries.

- Skill: `cwijayasundara/testing` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add cwijayasundara/testing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cwijayasundara/testing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: cwijayasundara (https://skillmd.com/u/cwijayasundara)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cwijayasundara/testing

---


# Testing Skill

Reference skill for generator teammates. Read this before writing any test code.

---

## Test Strategy

Tests run in three layers. Each layer has a distinct purpose and cost profile.

### Layer 1 — Unit Tests
- Test a single function or class in isolation.
- No network, no database, no file system.
- Mock only external boundaries (see code-gen SKILL.md for mock rules).
- Fast: all unit tests must complete in under 10 seconds total.
- Location: `tests/unit/` mirroring the source tree.

### Layer 2 — Integration Tests
- Test interactions between two or more modules (e.g., service + repository against a real test DB).
- Use a real database in a Docker container, not SQLite substitutes unless explicitly approved.
- Seed data is reset between tests using transactions or truncation.
- Location: `tests/integration/`.

### Layer 3 — End-to-End Tests (E2E)
- Test complete user flows through the running application.
- Use Playwright (see `references/playwright.md` for config and patterns).
- Run against a locally started application with a seeded test database.
- Location: `tests/e2e/`.

---

## Coverage Requirements

| Layer | Minimum Threshold |
|-------|-------------------|
| Unit | 100% of business logic branches |
| Integration | All happy paths + documented error paths per endpoint |
| E2E | All user stories in the current sprint contract |

Coverage tools (pytest-cov, Vitest coverage) must pass CI gates. A failing coverage
gate blocks merge — it is not advisory.

---

## Boundary Condition Generation

For every function under test, generate test cases for:
1. **Empty inputs** — empty string, empty array, zero, null/None.
2. **Boundary values** — min/max valid range, one below min, one above max.
3. **Invalid types** — if the language allows runtime type errors, test them.
4. **Error paths** — every documented exception/error case must have a test.
5. **Concurrency** — if the function is called concurrently, test for race conditions.

Name boundary tests descriptively:
- `"returns empty list when no items match filter"`
- `"raises OrderNotFoundError when order_id does not exist"`
- `"caps quantity at MAX_ITEMS_PER_ORDER when input exceeds limit"`

---

## Test Data Rules

- Use realistic domain values in all tests. See `references/test-data.md` for fixture patterns.
- Never use placeholder values: `"test"`, `0`, `"foo"`, `null` as stand-ins for real domain objects.
- Use factory functions or builder patterns to construct test data — not inline object literals.
- Randomize test data where possible using seeded fakers (Faker.js, Faker for Python).
  - Seed the faker in CI to get deterministic results (`faker.seed(12345)`).

---

## Gotchas

- Mocking business logic instead of testing it (hides bugs, creates false confidence)
- Writing tests that only test the happy path — error paths matter equally
- Using `time.sleep()` or `waitForTimeout` in tests — use proper async patterns
- Tests that depend on execution order — each test must be independently runnable
- Asserting on implementation details (private method calls) instead of observable outcomes
- Using production database credentials in any test environment
- Hardcoded port numbers without fallback — use dynamic port allocation in integration tests

