tdd · diff
v1.0.0 to v1.0.0
1 added, 1 removed. Audit A to A.
---
name: tdd
description: You MUST use this when implementing any feature, bug fix, refactor, or behavior change, especially when a test could fail for a setup reason, assert the wrong boundary, pass without proving the requirement, or cross module, API, external, state, security, or visual boundaries.
metadata:
author: Ihor Orlovskyi
version: "1.0.0"
license: MIT
---
- # TDD: Test-Driven Development
+ # TDD — Test-Driven Development
## Overview
Use this skill to drive one concrete behavior into existence through a focused test-first
cycle. The cycle is:
```text
BEHAVIOR -> RED -> VERIFY RED -> GREEN -> VERIFY GREEN -> REFACTOR -> VERIFY GREEN
```
The test is evidence only when it observes the promised behavior at the right boundary and
can fail for a meaningful defect. A green test is evidence only when its oracle proves the
requirement rather than an implementation shape.
This method is framework-neutral. Identify the repository's test tooling and delegate its
commands and mechanics to the applicable project skill.
## When to Use
Use this skill for:
- new behavior and feature work;
- bug fixes and regression tests;
- refactors that must preserve behavior;
- changes to APIs, state transitions, validation, authorization, persistence, or external adapters;
- test changes whose oracle, boundary, mocks, setup, or determinism could be misleading.
Route purely mechanical changes with no behavior to the appropriate project workflow. For
generated output or configuration, apply TDD when the change has a behavior contract; otherwise
use the project's direct verification convention.
## The Iron Law
```text
NO NEW PRODUCTION BEHAVIOR WITHOUT A VALID BEHAVIORAL RED FIRST
```
For new behavior, writing production code before the valid RED invalidates the cycle. Delete
or discard the untested implementation and restart from the test. Do not keep it as a reference,
adapt it while writing the test, or treat a manual check as a substitute.
If the behavior was already present before the current task, an initial test may be GREEN.
Investigate whether the requirement is already satisfied, the test is weak, or the boundary is
wrong. Preserve existing behavior while investigating; reserve discard-and-restart for code
introduced prematurely for the current change.
This law applies to a bug fix through its corrected regression RED. It does not require deleting
legacy production code during a refactor; use Characterization Mode below.
## The Enhanced Cycle
### 1. Define the behavior and acceptance boundary
Translate the requirement in this order:
```text
requirement -> observable behavior -> acceptance boundary -> test
```
Before writing the test, answer:
```text
What observable behavior proves that this requirement is satisfied?
```
Name the input, action, boundary, and outcome. Prefer client-visible results, persisted state,
emitted messages, status codes, domain errors, state transitions, or real component behavior.
Check existing tests first so a new test adds evidence instead of repeating coverage.
An assertion about a function existing, output shape, mock calls, incidental text, or internal
state is insufficient when the requirement promises a usable workflow. Such an assertion is
valid only when that shape, text, interaction, or state is itself the public contract.
### 2. Select the lowest sufficient test level
Choose the lowest level that still observes the real behavior:
| Behavior boundary | Starting level |
| --- | --- |
| Pure deterministic logic | Unit |
| Module collaboration | Integration |
| HTTP or API contract | API or integration |
| Component interaction | Component or browser |
| Full user workflow | E2E |
| External dependency contract | Contract or integration |
Use the real boundary that owns the promise. A unit test is insufficient when the requirement
exists only across modules, middleware, persistence, or a network adapter. E2E is unnecessary
when a lower level observes the same contract with less setup and more diagnostic signal.
### 3. Assess risk and required depth
Keep the TDD cycle for every behavior change. Scale the supporting evidence with risk:
| Risk | Minimum depth |
| --- | --- |
| LOW | Primary behavior and obvious boundary cases |
| MEDIUM | Primary behavior, important errors, boundary values, and meaningful interactions |
| HIGH | Positive and negative paths, authorization or security, state transitions, recovery, integration boundary, and important regressions |
Treat authentication, authorization, payments, data loss, migrations, permissions, concurrency,
critical business logic, and public APIs as high risk. See
[test-quality.md](references/test-quality.md) for the detailed depth and oracle guidance.
For multiple acceptance criteria, make a lightweight map:
```text
REQ-1 -> observable behavior -> test evidence
REQ-2 -> observable behavior -> test evidence
REQ-3 -> manual or visual evidence, when automation cannot observe it reliably
```
Before completion, ask whether every relevant acceptance behavior has convincing evidence.
### 4. Write a focused RED
Write one test for one behavior. Give it a name that describes the promised outcome and use
literal, independently derived expected values. Keep real code under test; add a double only
when the dependency boundary justifies it.
Before running the test, record a short failure contract:
```text
Expected RED
- Behavior: the observable promise under test
- Assertion: the assertion expected to fail
- Reason: the missing or wrong behavior causing that failure
- Command: the narrow command that runs this test
```
For a bug, the regression RED describes the corrected outcome. For a new behavior, the test
must be written before the corresponding production behavior exists.
### 5. Verify RED for the right reason
Run the targeted command and compare the result with the failure contract. Valid RED requires
all of these:
- the intended test was collected and executed;
- the intended behavioral assertion failed;
- the failure shows the behavior is missing or wrong;
- the test setup reached the acceptance boundary;
- the failure is reproducible enough to trust.
Record concise evidence:
```text
Observed RED
- Command: <targeted command>
- Result: <test and assertion that failed>
- Cause: <missing or wrong behavior>
```
These results are invalid RED:
- module-not-found, syntax, configuration, fixture, or test-collection errors;
- environment failures, unrelated suite failures, network outages, or unrelated timeouts;
- the wrong assertion failing;
- a mock or setup failure that prevented the real behavior from running;
- a nondeterministic failure that has no stable behavioral explanation.
Fix the test or setup and rerun when RED is invalid. Route an unexpected failure to
`systematic-debugging` rather than guessing at a production fix. If the test is immediately
GREEN, investigate whether the behavior already exists, the requirement is already satisfied,
the test is weak, or the boundary is wrong. Do not manufacture a failure for ceremony.
### 6. Implement minimum sufficient behavior
Write the smallest general implementation that satisfies the requirement and the RED. Minimum
means a real solution for the behavior, not a hardcoded example, test-specific branch, fake
return, or implementation that handles only current fixtures.
Do not add speculative options, unrelated refactors, or public surface that the behavior does
not need. If the test is difficult to express, treat that pressure as design feedback and
consider a simpler boundary before adding production-only test seams.
### 7. Verify GREEN and inspect change impact
Run the targeted test first. GREEN means both conditions hold:
```text
required behavior exists
AND
the intended test passes for the intended reason
```
Then inspect what the implementation could affect. For changes to a shared helper, type, public
API, base component, configuration, parser, schema, or common utility, run targeted regression
checks for relevant dependents. Do not use a full repository run after every micro-cycle without
a reason; broad final verification belongs to the completion workflow.
If GREEN fails, fix the implementation or the real test seam. Do not weaken the assertion to
match the current code.
### 8. Refactor under green pressure
Refactor only after GREEN. Inspect both production design and test design:
- Can the implementation become simpler?
- Did GREEN introduce duplication or unclear names?
- Did test pressure create an awkward production API or unnecessary public surface?
- Are tests coupled to private structure, exact call choreography, or incidental wording?
- Does the test communicate the behavior and survive reasonable refactoring?
Refactoring may improve structure and clarity; it does not add behavior. Rerun the relevant
tests after every refactor and keep the intended GREEN evidence.
### 9. Check sensitivity before the next behavior
Ask:
```text
Would this test fail if the behavior were meaningfully broken?
```
Use a mental mutation check for normal-risk work. Consider mutations such as a wrong branch,
changed boundary value, missing validation, skipped state change, empty return, wrong error,
or a side effect being removed. For high-risk behavior or a suspiciously weak test, introduce
one small meaningful defect temporarily, run the targeted test to confirm RED, then revert it.
Use an existing targeted mutation tool when the project already has one. Full mutation testing
is optional.
## Conditional Modes
### Characterization Mode for legacy code
Use this mode for a legacy refactor whose intended behavior predates the current change:
```text
identify intended existing behavior -> write characterization tests -> check sensitivity
-> refactor -> keep the characterization suite green
```
Capture observable behavior at the public boundary. If existing behavior is a known bug, record
it as a defect and write a corrected regression RED. Do not freeze the bug as an intended
compatibility contract, and do not use characterization mode to add new behavior after coding.
### Property or invariant testing
When behavior spans a wide input space, ask whether an invariant carries more evidence than a
few examples. Consider property-based tests for parsers, serializers, sorters, converters,
validators, financial calculations, normalizers, and state machines. Useful invariants include
round-trip preservation, sorted output, length preservation, idempotence, and unreachable
invalid states. Use properties when they strengthen the oracle; examples remain useful for
named boundary cases.
### External contract boundaries
Model the boundary explicitly:
```text
external service -> project adapter -> domain behavior
```
Test the contract owned by the adapter or domain. Keep slow, unavailable, or destructive
external operations behind a justified boundary double. Do not reproduce SDK internals in
unit tests or assert a mock back to itself. When a mock is needed, mirror the real response
structure and preserve side effects the behavior relies on.
### Determinism and flakiness
RED or GREEN is evidence only when the targeted test is deterministic enough to trust. Signals
include timing dependence, test-order dependence, local timezone dependence, random state,
network dependence, shared global state, and intermittent pass/fail results.
Repeat the targeted test enough to detect instability when a flake is suspected. Never use
retry-until-green as a workaround. Stabilize the cause with a controlled clock, deterministic
seed or input, isolated state and cleanup, a controlled network boundary, or explicit async
synchronization. If the failure still lacks a behavioral explanation, use
`systematic-debugging`.
### Human and visual acceptance
Separate claims that automation can observe from claims that require a person or a rendered
browser surface. Visual hierarchy, responsive composition, animation quality, browser rendering,
and subjective usability need a manual or visual verification companion. Do not convert a
visual promise into a weak DOM assertion for the sake of a green test.
When manual verification finds a reproducible behavior defect, turn that defect into a new RED
whenever an automated oracle can observe it.
## Composition Boundaries
| Concern | Owner |
| --- | --- |
| Required outcome, acceptance criteria, scope, and file map | `plan-crafting` |
| Task ordering, execution mode, task ledger, and subagent orchestration | `executing-plans` or `subagent-driven-development` |
| Test-first development of one behavior | `tdd` |
| Root-cause investigation for an unexpected failure | `systematic-debugging` |
| Framework mechanics and project-specific test commands | Specialized project skill such as `vitest` |
| Browser-driving checks and console evidence | `web-debug` |
| Visual design quality and frontend review | `frontend-crafting` |
| Broad final verification and completion claims | The project's completion verification workflow |
`tdd` supplies the method inside an implementation task. It does not create a large plan,
orchestrate agents, create `.sdd/`, perform whole-branch review, or replace final verification.
## Evidence Template
For each completed micro-cycle, retain concise evidence when the workflow supports it:
```text
Behavior: <observable promise>
Boundary: <unit, module, API, component, browser, E2E, or contract>
Risk: <low, medium, or high and why>
RED command: <targeted command>
Expected RED: <assertion and behavioral reason>
Observed RED: <short failure evidence>
GREEN command: <targeted command>
Observed GREEN: <short pass evidence>
Impact checks: <relevant dependents or none>
Refactor check: <design and test quality result>
Sensitivity: <mental or targeted mutation result>
Manual evidence: <required evidence or not applicable>
```
Do not store huge raw logs when a short relevant result proves the gate.
## Anti-Patterns
Stop and correct the cycle when you see:
- production behavior written before a valid RED;
- tests added after implementation as the primary evidence;
- RED caused by broken setup, infrastructure, or an unrelated assertion;
- assertions about implementation details while the requirement concerns user-visible behavior;
- mocking the component or decision under test;
- a test that passes while the promised behavior is broken;
- hardcoding production behavior to current examples;
- treating coverage percentage as proof of oracle quality;
- retrying until green instead of fixing nondeterminism;
- using E2E where a lower sufficient boundary gives stronger signal;
- unit-testing an integration contract that exists only at a higher boundary.
## Completion Checklist
Before handing the behavior to the execution or completion workflow, confirm:
- [ ] Requirement is translated into observable behavior and an acceptance boundary.
- [ ] Existing coverage was checked and duplicate tests add a stated value.
- [ ] Test level is the lowest level that observes the real behavior.
- [ ] Risk depth covers the relevant positive, negative, boundary, interaction, security,
state, recovery, or integration cases.
- [ ] A focused test was written before new production behavior.
- [ ] Expected RED named the assertion and behavioral reason.
- [ ] Observed RED was the expected behavioral failure, with setup failures excluded.
- [ ] GREEN proves the promised behavior, with independently derived expectations.
- [ ] Changed dependents received targeted regression checks.
- [ ] Refactor improved design or test quality without adding behavior, and GREEN was rerun.
- [ ] Sensitivity was checked mentally or with one targeted real mutation when risk warranted it.
- [ ] Property, contract, determinism, and manual or visual modes were considered where relevant.
- [ ] Framework mechanics and broad final verification were delegated to their project workflows.
If a required gate lacks evidence, keep the behavior open and report the gap. A green command
alone does not close an unproven acceptance criterion.