Drives development through red-green-refactor cycles where you write a failing test that names the desired behavior before writing any implementation code. TDD produces tests that document intent, catches regressions immediately, and forces small, verifiable increments—making it especially valuable for complex features, bug fixes with known failure cases, and any code that needs a long-term safety net.
Use cases
- Building a new module where behavior is well-defined but the implementation is not yet clear
- Fixing a regression bug—write the test that would have caught it before patching
- Refactoring legacy code that lacks tests and needs a characterization suite first
- Implementing an algorithm from a specification and wanting to verify correctness incrementally
- Adding a feature to a codebase with a low test coverage history
Key features
- Write a single failing test that describes the next piece of behavior you want to see, using the API as the caller would
- Run the test to confirm it fails with a clear, expected error—red light confirming the behavior is not yet present
- Write the minimum implementation needed to make the test pass, resist adding functionality beyond the test's scope
- Refactor the code while keeping all tests green—use the safety net to improve structure without changing behavior
- Repeat the cycle until the feature is complete, then add integration tests that cover the wiring between units
When to Use This Skill
- When implementing a new feature with clear acceptance criteria and testable behavior
- When fixing a bug that has a reproducible failure case
- When refactoring code with no existing test coverage and wanting a safety net
Expected Output
A passing test suite organized in unit and integration layers, with each test name describing expected behavior rather than implementation details.
Frequently Asked Questions
- Does TDD slow down initial development noticeably?
- It shifts the cost: you spend more time upfront writing tests but significantly less time debugging later. For projects with a maintenance horizon beyond a few weeks, this trade-off typically pays for itself.
- What do I do when a test is hard to write because the dependency is a UI or database?
- Use test doubles (mocks, stubs, fakes) to isolate the unit under test. If the full stack is needed for verification, write a thin integration test at the outer layer and keep unit tests for the logic core.
- How do I apply TDD to AI-assisted coding where the model generates code quickly?
- Write the test prompt first, then ask the model to implement only enough to pass that specific test. This prevents the common AI pattern of generating verbose infrastructure that then needs retrofitting.
Related
Related
3 Indexed items
Safe refactoring
Executes refactoring changes in small, test-backed steps so behavior is preserved while structure improves. Each refactoring operation—rename, extract, inline, move—is validated by the test suite before proceeding to the next, preventing the common pattern of refactoring into subtle behavioral regressions that are only caught in production.
Executing implementation plans
Executes a pre-written implementation plan in disciplined order, stopping at defined checkpoints to verify assumptions before moving forward. This skill prevents the common pattern of diverging from the plan silently when reality proves it wrong, and it creates natural opportunities to course-correct before small errors compound into large rework.
Contract testing
Locks API expectations between services using consumer-driven contracts so that when one team changes their implementation, it fails in CI rather than during a coordinated production deployment. Contract testing prevents the common integration failure pattern where both sides of an API appear to work in isolation but break when connected in production.