Writing Tests
Critical rules
- Names describe outcomes, not actions:
[outcome] when [condition]— e.g.returns empty array when input is null, nottest null input. - Assertions match the title. If the name claims "different IDs", assert the IDs differ — not just length.
- Assert specific values, not
toBeDefined()/toBeTruthy(). Specific assertions catch specific bugs. - One concept per test. If you need "and" in the name, split.
- Bugs cluster. One bug → test related inputs, same pattern elsewhere, same assumption, same type.
- Assert behavior (Results, returned values), not implementation (
toHaveBeenCalledWithfor SQL shape). - No
vi.mock()for app logic —mock<DepsType>()from vitest-mock-extended. - Before WRONG/CORRECT examples or edge-case checklists, read the matching resource below.
Workflow
- Name the test as a specification: reading names alone should describe the function.
- Structure Arrange → Act → Assert. Keep one reason to fail.
- For
Result<T, E>: assertresult.okand the exacterrororvalue. - Cover relevant edge cases (numbers, strings, collections, dates, null/undefined, domain constraints). Before expanding coverage, read references/edge-cases.md.
- On a bug fix: add the failing case, then neighbors (null→undefined→empty; same boundary elsewhere).
- Prefer observable outcomes over internal call assertions so refactors don't break tests.
Adapted from BugMagnet (Gojko Adzic), aligned with fn(args, deps) and Result patterns.
Resources
- references/examples.md — naming, assertions, Result tests, AAA, complete getUser suite. Read when drafting or reviewing a test.
- references/edge-cases.md — type and domain checklists. Read when expanding coverage.
- references/rationalizations.md — excuse→reality and red flags. Read when tempted to weaken a test.
Validation
- Names use
[outcome] when [condition] - Each assertion verifies the title's claim with specific values
- One concept per test (no "and" in the name)
- Result tests assert
okand exact error/value - Relevant edge cases covered; bug fixes spawned cluster tests
- Behavior asserted, not brittle internal calls; deps via
mock<DepsType>()
Constraints
- Layer choice (unit vs integration vs e2e) is
testing-strategy, not this skill. - Red-green-refactor discipline is
tdd-workflow(this skill is RED-phase craft). - Adjacent:
result-types,validation-boundary,fn-args-deps,design-principles(hard-to-test often means design smell).