testing-principles · git:20261013.5482041 · 2026-10-13 · sha256 591da4ef5b884a27

testing-principles git:20261013.5482041A

Immutable. This exact content never changes and is served at /api/v1/blob/591da4ef5b884a27.

---
name: testing-principles
description: Language-agnostic testing principles for choosing which tests a change needs, test quality, and proof ownership, with frontend and browser E2E implementation references. Use when writing tests, deciding test scope, or reviewing test quality.
---

# Language-Agnostic Testing Principles

Tests here guarantee accepted behavior, and the next agent reads every existing test as a requirement to preserve. A brittle, duplicated, or implementation-shaped test therefore becomes a false requirement: it gets worked around, and the workaround leaves debt in the implementation. Keep the set of tests whose proof is worth its maintenance.

## Test Selection

- Prove accepted behavior by default through integration and E2E tests at the boundary users and callers observe. Add a unit test for logic whose cases one representative boundary test cannot prove, such as calculations, parsing, or branching rules.
- Each behavioral claim is owned by one test: such logic by its unit test, other behavior by the test at the narrowest integration or E2E boundary where it is observable. A test at a wider boundary or in a variant (viewport, device, role) proves what that boundary or variant adds, such as wiring, mapping, persistence, rendering, or navigation, and keeps at most one representative case of a rule owned elsewhere.
- Treat coverage as a diagnostic signal for finding untested areas, not a target; any CI threshold is the project's config, not a quality goal in itself.
- Use project-configured speed budgets when present. Otherwise investigate test speed only when observed feedback or CI cost is material to the current outcome; retain slower tests when their proof boundary requires it.

## Test Design Rules

- Structure each test as Arrange, one Act, and Assert; multiple assertions may prove one behavior.
- Follow the repository's test naming convention and name the condition and observable outcome.
- Exercise behavior through a public or integration boundary. Assertions verify return values, outputs, errors, or state changes rather than private implementation.
- Use independently derived literal, property, approved snapshot, or fixture expectations. An implementation-derived oracle cannot detect the same implementation defect.
- Keep each test's expected outcome unconditional. Table-driven or property-based cases are acceptable when each case is reported distinctly and uses an independent oracle.
- Cover accepted boundary and error behavior; derive cases from the contract instead of adding generic edge-case permutations.
- Each test creates and cleans up its own state, passes in isolation and any order, and controls time or randomness that affects its result.
- Keep tests executable. Fix or remove tests that no longer describe accepted behavior; restore tests disabled only to bypass a failure.

## Mock and Boundary Rules

- Mock direct external I/O boundaries; keep internal business logic and the boundary under test real.
- Use the existing application-owned adapter as the mock boundary. Introduce an adapter only when external I/O, an unstable contract, or required substitution cannot be controlled through the current design.
- Keep mock behavior limited to the contract needed by the test.

## Data Layer Testing

Mock-based tests are sufficient when data access is only a dependency of the behavior under test. Verify against the project's real database engine or its accepted equivalent when the subject is a query, repository implementation, schema constraint, or migration compatibility. Resolve the test environment from repository configuration; when no representative environment exists and adding one is outside the approved work, report the missing verification decision.

Cross-check data-access code against the schema source named in the Design Doc or repository configuration. Schema-source verification is required to prove table, column, type, constraint, or dialect compatibility; successful mocks prove behavior only at the mocked boundary.

## Verification Requirements

### Capability Probe Postconditions

A capability probe passes when it uses the consumer's boundary and asserts the exact property that consumer needs. Command success, import success, or object existence is setup evidence.

## Test Organization

Follow the repository's established test paths, runner routing, and naming. When establishing an approved new convention, separate test types only when their setup, runner, or environment differs.

## Regression Testing

- Add a regression test for every reproducible behavior bug fix. When executable reproduction is impossible, record the reason and the alternative static, contract, or environment evidence that prevents recurrence.
- Before behavior-preserving changes to uncharacterized legacy code, establish passing characterization evidence and rerun it after the change.

## References

- [references/frontend.md](references/frontend.md): read when writing, changing, or reviewing component, hook, or UI integration tests
- [references/e2e.md](references/e2e.md): read when writing, changing, or reviewing browser E2E tests