All topics
Testingintermediate

Test-Driven Development (TDD)

A development workflow where a failing test is written before the implementation code, following a strict red-green-refactor cycle.

Test-Driven Development is a workflow — not just a testing technique — where you write a failing test *before* writing the implementation code that makes it pass, following a disciplined, repeating three-step cycle often summarized as 'red, green, refactor.' It's as much a design practice as a correctness-verification practice, and interviewers ask about it to gauge whether you understand the workflow's actual purpose beyond just 'writing tests early.'

TDD is like a sculptor who first describes precisely, in words, exactly what the finished statue's specific pose and expression should look like (the failing test) before touching the marble, then carves only enough to match that exact description (minimal implementation), and only afterward smooths and polishes the surface (refactor) — confident that the carved shape's core measurements already match the original written description, checked and rechecked, throughout the smoothing process.

Key Concepts

1
The cycle starts red: write a small test describing one specific piece of desired behavior that doesn't exist in the code yet, run it, and confirm it fails (if it doesn't fail, either the behavior already exists or the test itself is broken and testing nothing meaningful). Then green: write the minimal amount of implementation code necessary to make that specific failing test pass — deliberately minimal, resisting the urge to build out more functionality than the current test actually demands, even if you can already anticipate needing it soon. Finally refactor: with a passing test now acting as a safety net, clean up the implementation (and/or the test) for clarity and remove duplication, re-running the test after each small change to confirm it still passes throughout.
redgreenrefactor
2
The claimed benefits go beyond simply 'having tests': writing the test first forces you to think through a piece of code's intended interface and behavior from the calling code's perspective before getting absorbed in implementation details, which often surfaces awkward API design early, when it's cheap to change, rather than after a lot of code already depends on a clunky shape. The discipline of only writing the minimal code to pass the current test also naturally guards against speculative over-engineering — building flexibility or features nobody has actually asked for yet, sometimes called 'YAGNI' (you aren't gonna need it) violations.
3
TDD is not universally practiced, and its value is genuinely debated even among experienced developers — critics point out it can slow down initial exploratory work where the right design isn't yet clear, and that 100% strict adherence to 'never write code without a failing test first' is more rigid than most teams actually sustain in practice. A pragmatic, common middle ground many teams land on is writing tests very close in time to the implementation (before, during, or immediately after) rather than treating strict TDD as an absolute, non-negotiable rule for every single line of code.