test-driven development (TDD)
Test-driven development, or TDD, is a way of building software in which a failing automated test is written first and the code that makes it pass comes second. Kent Beck popularized it as part of Extreme Programming in the late 1990s, and it interleaves three activities that teams often keep separate: testing, coding, and design.
Each pass through the practice is a short loop called red, green, refactor:
- Red: Write one small test for behavior that doesn’t exist yet, then run it and watch it fail.
- Green: Write the least code that makes the test pass, even when that code is crude.
- Refactor: Clean up the result now that a test protects the behavior.
Skipping the third step is the most common way the practice goes wrong. Martin Fowler notes in his entry on the practice that neglecting the refactoring step leaves messy code, though at least the mess has tests around it.
How It Shows Up in Practice
Say a developer is extending a helper that formats a track length and needs it to handle durations past a minute. Under TDD, the assertion that describes the new behavior gets written before any of the code that satisfies it:
test_duration.py
from duration import format_duration
def test_formats_minutes_and_seconds():
assert format_duration(95) == "1:35"
The module currently handles only durations under a minute, so format_duration(95) comes back as '0:95', and running pytest produces the red step:
$ python -m pytest -q
F [100%]
...
> assert format_duration(95) == "1:35"
E AssertionError: assert '0:95' == '1:35'
...
1 failed in 0.03s
That failure is the specification, stated precisely enough to code against. Green means changing duration.py until this one assertion passes and nothing more:
duration.py
def format_duration(seconds):
minutes, remaining = divmod(seconds, 60)
return f"{minutes}:{remaining:02d}"
The same command now reports the green step:
$ python -m pytest -q
. [100%]
1 passed in 0.01s
Refactoring happens here, with the test standing guard, and the next behavior starts the loop again. A Python developer runs through this cycle many times an hour, usually against pytest or unittest, so the tests stay small and the feedback stays quick.
Step through two turns of that loop below, watching the test file, the source file, and the pytest run change one phase at a time:
Why Teams Adopt It
The first payoff is design pressure. Writing the test first forces a decision about how the code will be called before any of it exists, so the interface gets shaped by its first caller instead of being retrofitted afterward.
The second payoff is a regression suite that accumulates as a by-product. Every cycle leaves another test behind, and that suite is what continuous integration runs on each change. Those tests sit at the wide base of the test pyramid, fast enough to run constantly.
The Agile Alliance reports that teams practicing TDD see meaningfully lower defect rates for a moderate increase in up-front effort. It also catalogs the familiar failure modes: running the suite rarely, writing a batch of tests at once instead of one, testing trivial accessors, and letting the suite decay until it runs too slowly to be useful or gets abandoned altogether.
TDD drives the design of a single unit. Behavior-driven development applies the same test-first instinct to a whole feature, phrased in language the business side can read.
Related Resources
Course
Test-Driven Development With pytest
In this hands-on course, you’ll see how to create Python unit tests, execute them, and find the bugs before your users do. You’ll learn about the tools available to write and execute tests, check your application’s performance, and even look for security issues.
For additional information on related topics, take a look at the following resources:
- pytest Tutorial: Effective Python Testing (Tutorial)
- Python's unittest: Writing Unit Tests for Your Code (Tutorial)
- Python's assert: Debug and Test Your Code Like a Pro (Tutorial)
- Write and Test a Python Function: Interview Practice (Course)
- How to Provide Test Fixtures for Django Models in pytest (Tutorial)
- Testing Your Code With pytest (Course)
- Effective Testing with Pytest (Quiz)
- Testing Your Code With Python's unittest (Course)
- Python's unittest: Writing Unit Tests for Your Code (Quiz)
- Using Python's assert to Debug and Test Your Code (Course)
- Python's assert: Debug and Test Your Code Like a Pro (Quiz)
Have a question about this? Mentor AI can show you examples, compare related terms, and point you to tutorials.
By Martin Breuss • Updated Oct. 3, 2026