awesome-everything RU
↑ Back to the climb

Engineering Practice

TDD: build a suite that would notice the bug

Crux Hands-on project — drive a small domain module test-first, harden it with the boundary rule and a property test, then prove suite quality with a mutation score, not coverage.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 240 min

Reading about test quality is not the same as building a suite that earns trust. Take a small but boundary-rich module, drive it test-first, harden it with the unit’s techniques, and then prove the suite is real by measuring whether it would notice a bug — with evidence at every step.

Goal

Turn the unit’s mental model into a repeatable engineering loop: design under test-first pressure, apply the boundary rule to doubles, add a property where examples are weakest, and use a mutation score (not coverage) to prove the suite would catch a regression.

Project
0 of 7
Objective

Build a small domain module test-first (a money/discount engine, a date-range or rate-limit rule, or a parser of your choice), then prove the test suite's quality with a mutation score above target — not a coverage number — applying the boundary rule, a property test, and a documented spec-stability decision.

Requirements
Acceptance criteria
  • A before/after table for the module: line coverage, mutation score, and survivor count — measured by the tool, not estimated — with mutation score on the critical logic above your stated target (e.g. ≥85%).
  • Git history (or an equivalent log) shows the red-green-refactor order: a failing test committed before its implementation for at least one rule.
  • A one-line justification per double showing the boundary rule applied — which collaborators are real, which are stubbed, and why each is correct.
  • The property test runs ≥500 cases with a recorded seed, and you can name which property shape it is and one bug class it guards that the example tests didn't.
  • A short write-up: which survived mutants you killed and how, which (if any) you triaged as equivalent and why, and the one spec-stability decision with its reasoning.
Senior stretch
  • Wire mutation testing into CI as a diff-based gate (Stryker/PIT incremental) that fails the build if a changed file's mutation score drops, and show it catching a deliberately weakened assertion.
  • Add an oracle property that runs your module against an independent reference implementation (a slow obvious version, or a second library) over generated input, and shrink a planted divergence to its minimal counterexample.
  • Take one over-mocked test from an existing codebase, rewrite it under the boundary rule, and show it now survives a behavior-preserving refactor while still failing on a real injected bug.
  • Write a one-page team note: when to TDD versus spike on your codebase, the boundary-rule checklist for doubles, and how you scope mutation testing so it pays off without taking hours per run.
Recap

This is the loop you will run on any module that matters: design under test-first pressure so the interface is right before it has call sites, apply the boundary rule so doubles don’t pin you to structure, add a property where your examples are weakest, and then prove the suite with a mutation score rather than trusting coverage — reading the survivors as a list of missing assertions. The spec-stability decision keeps you honest about where TDD pays and where a spike is the right tool. Do it once on a small module and the production version becomes muscle memory.

Continue the climb ↑The integration-testing dilemma
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.