test-driven-development — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited test-driven-development (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
TDD is design discipline through the test-writing lens. The unit of work is the red-green-refactor cycle: write one failing test for one increment of behavior (red), write the smallest production change that makes it pass (green), restructure the shape of both code and test while keeping all tests passing (refactor). Each cycle fits in a few minutes; long cycles indicate either insufficient test granularity or production complexity that should be decomposed. The test suite is the design pressure that shapes production code — writing tests first surfaces hard-to-test code at the moment when the underlying design discomfort (hard-to-use, hard-to-compose, hard-to-maintain) is still cheap to correct.
Replaces test-after-implementation with test-driven design pressure. Solves the problem that tests written after the code mirror the implementation rather than the desired behavior — they lock the current shape in place, fragment under refactor, and miss the design feedback that comes only from articulating what a unit should do before writing it. Industrial evidence (Nagappan et al. 2008 at Microsoft and IBM across four teams) shows TDD codebases have 40-90% lower defect density at 15-35% longer initial development time; Erdogmus et al. (2005), Janzen & Saiedian (2008), and Bissi et al. (2016) converge on the same direction. Replaces "tests as regression coverage" with "tests as design pressure that produces regression coverage as a side effect."
Distinct from testing-strategy, which owns the strategic question of what to test, at which level, with what evidence — strategy decides the surface, TDD prescribes the rhythm within it. Distinct from test-doubles-design, which owns mocks/stubs/fakes/spies as constructs — TDD's schools differ on how much test-doubles design matters to the practice (London heavily, Detroit lightly); the two compose. Distinct from eval-driven-development, the LLM analog where the unit of judgment is pass-rate over a sample rather than binary per-test pass/fail — both share the iteration-first-then-implement spirit but the math underneath differs. Distinct from refactor, which owns behavior-preserving structural change as a technique — TDD calls refactor as the third beat of red-green-refactor; refactor owns how to do it without breaking behavior. Distinct from the obra/superpowers TDD workflow skill on skills.sh, which is workflow-shape (process steps); this skill is concept-shape (the discipline's underlying mechanism). TDD is to code design what a piano teacher's metronome is to a student's playing — the rhythm is not the music, but it surfaces every uneven phrase, every rushed measure, every hesitation, in time to correct it before it ossifies into habit. The wrong mental model is that TDD is "writing tests first" as a procedural rule, where the tests are the point and the production code merely satisfies them. They are not the point. Tests are an artifact of doing design with a test-shaped tool; a team that "does TDD" by writing tests first without heeding the design pressure has the artifact without the practice, and will conclude TDD doesn't work because they will see only the cost (slower initial development) without the benefit (better-shaped code with lower defect density). Two adjacent misconceptions: that high coverage is the goal (coverage is a side effect; engineering tests to satisfy a coverage number Goodharts the discipline), and that the school doesn't matter (a practitioner who has not chosen London or Detroit has chosen by accident — the test suite's character, mock-rich vs state-rich, interaction-heavy vs state-heavy, reveals which school is in use whether the team named it or not).
The design discipline of writing the test before the production code that satisfies it, using the test-writing pressure to shape the code's design, and applying the red-green-refactor cycle as the unit of work. Covers the cycle structure (red → green → refactor), the design-pressure mechanism that makes TDD a design discipline rather than just a test-first habit, the London/Detroit/Chicago school distinctions (mockist vs classicist, outside-in vs inside-out, interaction vs state), the relationship between TDD and emergent design, the empirical record (Nagappan 2008 at Microsoft/IBM and meta-analyses since), the boundary between TDD and BDD, and the failure modes (skipping refactor, ignoring design pressure, mock-heavy fragile tests, coverage-as-goal Goodharting).
TDD is design through the test-writing lens. Every test you sit down to write is a moment of design: what is this unit, what does it own, what does it delegate, what does its interface look like from the outside. The discomfort of writing a hard-to-test piece of code is the same discomfort that will eventually arrive as hard-to-use, hard-to-maintain, hard-to-compose code; TDD makes that discomfort visible at the moment when correcting it is cheap.
The tests are not the point. The tests are an artifact of doing design with a test-shaped tool. A team that "does TDD" by writing tests first without heeding the design pressure has the artifact without the practice; they will conclude TDD doesn't work because they will see only the cost (slower initial development) without the benefit (better-shaped code with lower defect density).
The schools matter. London and Detroit produce different code under the same red-green-refactor cycle, because they apply the design pressure to different surfaces. A practitioner who has not chosen a school has chosen by accident, and the test suite's character — interaction-heavy or state-heavy, mock-rich or mock-sparse, outside-in or inside-out — reveals which they chose without knowing.
| Beat | Activity | Stop condition | Common mistake |
|---|---|---|---|
| Red | Write one failing test for one increment of desired behavior | The test compiles and fails for the right reason (not a syntax error) | Writing a passing test (no design pressure); writing many tests at once (loses the increment) |
| Green | Write the smallest production change that makes the test pass | The test passes; no other tests broke | Writing more than needed; "fake it till you make it" abandoned too early |
| Refactor | Improve the shape of both code and test while keeping all tests passing | The structure is cleaner; tests still pass | Skipping this beat; refactoring into bigger changes that break tests |
Each cycle should fit in a few minutes — long cycles indicate either insufficient test granularity or production complexity that should be decomposed before continuing.
| Property | London (mockist, outside-in) | Detroit (classicist, inside-out) |
|---|---|---|
| Origin | Freeman & Pryce, GOOS (2009) | Beck, TDD by Example (2002) |
| Starting point | Acceptance test or service boundary | A single concrete unit |
| Test focus | Interactions (who called whom with what) | Observable state changes |
| Test doubles | Central — every new collaborator becomes a mock | Sparse — used only when needed (DB, external service) |
| Design pressure | On collaborator interfaces (the mocks shape them) | On units' responsibilities and state shape |
| Failure mode | Tests mirror implementation; refactor breaks them | State assertions get coarse; design coupling grows |
| Typical codebase | Many small classes with well-defined collaboration roles | Fewer larger classes with rich state |
A practical heuristic: London-school suits services with rich collaboration (microservices, hexagonal architectures); Detroit-school suits state-rich domains (calculators, domain logic, parsers). Hybrid is the working norm.
Use TDD when the next behavior can be named before the implementation exists and feedback can arrive quickly enough to shape the code. Do not force it onto exploration where the target behavior is still unknown; spike first, then restart with tests once the behavior is nameable.
| Situation | TDD fit | Reason |
|---|---|---|
| New behavior with a clear externally observable contract | Strong | The failing test can state the desired behavior before implementation details exist |
| Bug fix with a reproducible example | Strong | The regression test becomes the red step, then green proves the bug is fixed |
| Refactor with behavior already pinned | Supporting | Use TDD for new seams discovered during the refactor, but the refactor skill owns behavior preservation |
| Legacy code with no test harness | Characterize first | Golden-master or characterization tests may be needed before true TDD can begin safely |
| Research spike, unfamiliar API, or unclear product behavior | Weak until clarified | Exploration is legitimate; TDD starts once the desired behavior can be expressed |
| Visual polish or copy-only work | Usually weak | The feedback signal is often review, screenshot comparison, or usability judgment rather than binary test failure |
| Failure mode | Symptom | Correction |
|---|---|---|
| Test-first without refactor | Red-green-next-red cycles pile up, design does not improve | Stop after green; refactor production and test code while the suite stays green |
| Implementation-mirroring tests | Every internal rename or extraction breaks tests | Rewrite tests around observable behavior and natural boundaries |
| Accidental school choice | Some tests mock every collaborator while others assert broad state with no rationale | Name the school per module and align doubles with the chosen design pressure |
| Coverage Goodharting | Tests are added to satisfy a number but do not describe meaningful behavior | Use coverage as a smoke alarm, not the target; require a behavior or regression reason |
| Slow cycles | A single red-green-refactor loop takes hours | Shrink the behavioral increment or decompose the production unit before continuing |
| TDD used instead of testing strategy | The team writes tests first but still chooses the wrong level of test | Load testing-strategy first to choose unit/integration/contract/e2e surface, then apply TDD rhythm inside that surface |
Multiple controlled studies and one large industrial study converge on a consistent directional finding: TDD codebases often show lower defect density at the cost of longer initial development time. Treat these numbers as evidence boundaries, not guarantees. The results depend on team discipline, cycle size, refactor quality, domain fit, and whether the team actually uses tests as design pressure rather than only as test-first paperwork.
| Study | Finding |
|---|---|
| Nagappan et al. (2008) at Microsoft and IBM | TDD teams had 40-90% lower defect density; 15-35% longer initial development time |
| Erdogmus et al. (2005) controlled experiment | TDD subjects had higher external code quality; productivity comparable |
| Janzen & Saiedian (2008) meta-analysis | Code complexity reduced; cohesion improved; coupling reduced under TDD |
| Bissi et al. (2016) systematic review | 27 of 39 studies showed TDD improved internal quality; 18 of 23 showed external quality improvement |
The trade is well-documented. Teams abandoning TDD often do so on the visible-cost side (the time spent writing tests) without measuring the invisible-saving side (defects not encountered, rework not required).
This public skill is reference-grounded and carries v6 understanding fields (mental_model, purpose, boundary, analogy, misconception), but its dedicated comprehension eval artifact is still planned. Keep eval_artifacts: planned, eval_state: unverified, and routing_eval: absent until a realistic eval suite exists, includes boundary/negative cases, runs in the same change, and produces evidence.
After applying this skill, verify:
calculateTotal() line 17."| Instead of this skill | Use | Why |
|---|---|---|
| Choosing what to test, at which level, with what evidence | testing-strategy | testing-strategy owns the strategic-level decision; this skill owns the tactical design discipline |
| Constructing a mock, stub, fake, or spy | test-doubles-design | test-doubles-design owns the constructs; this skill owns the discipline that places them |
| Iterating on LLM behavior using an eval suite | eval-driven-development | eval-driven-development is the LLM analog with statistical (not binary) judgment |
| Performing a behavior-preserving structural change | refactor | refactor owns the technique; this skill calls it as the third beat |
| Process workflow guidance for a TDD session | the obra/superpowers test-driven-development skill on skills.sh | that skill is the workflow-shape complement; this one is concept-shape |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.