Test-Driven Development in Python with pytest
Write the test, watch it fail, make it pass. TDD with pytest — the discipline that makes systems boring and reliable.
In this guide
Test-driven development flips the order: write the test first, watch it fail, then write the code to make it pass. It's the single habit that most improved the reliability of what we ship — we build every system this way.
The red-green-refactor loop
- Red — write a failing test.
- Green — write the minimum code to pass it.
- Refactor — clean up, keeping it green.
Write the failing test first
# test_cart.py
from cart import Cart
def test_add_item_increases_total():
cart = Cart()
cart.add("widget", price=5.0, qty=2)
assert cart.total() == 10.0
def test_remove_item():
cart = Cart()
cart.add("widget", price=5.0)
cart.remove("widget")
assert cart.total() == 0.0Run it — both fail, because Cart doesn't exist yet. That's the red.
Make it pass
# cart.py
class Cart:
def __init__(self):
self._items = {}
def add(self, name, price, qty=1):
self._items[name] = self._items.get(name, 0) + price * qty
def remove(self, name):
self._items.pop(name, None)
def total(self):
return sum(self._items.values())pip install pytest
pytest -q # 2 passed in 0.01sFixtures — shared setup
import pytest
@pytest.fixture
def cart():
c = Cart()
c.add("widget", price=5.0, qty=2)
return c
def test_total_with_fixture(cart):
assert cart.total() == 10.0Parametrise — many cases, one test
@pytest.mark.parametrize("qty,expected", [
(1, 5.0), (2, 10.0), (0, 0.0), (3, 15.0),
])
def test_total_for_qty(qty, expected):
cart = Cart()
cart.add("widget", price=5.0, qty=qty)
assert cart.total() == expectedTest behaviour, not implementation. If you have to rewrite a test every time you refactor, the test is too tightly coupled.
TDD isn't about more tests — it's about designing code you can prove. We've found the systems that rarely need maintenance are the ones built this way.
More from the lab
Serverless Functions with AWS Lambda & API Gateway
Run code with no servers to manage — a Lambda behind an API Gateway, gotchas explained.
SecurityThe OWASP Top 10: A Developer's Guide to Web Security
The ten most common web vulnerabilities, what each looks like in code, and how to fix them.
FrontendReact vs Vue vs Svelte: Choosing a Frontend Framework
A candid, no-hype comparison of React, Vue and Svelte — where each shines, and what to pick.
Want us to build this for you?
We turn tutorials like these into production systems every day. Tell us what you need.
Start a project →