Skip to main content
This lesson walks through a practical test-driven development (TDD) example using Claude Code to generate tests and iterate on an implementation. The sample project is a compact unit-converter supporting distance, volume, mass, and temperature conversions. TDD workflow recap:
  • Write tests first.
  • Run tests and watch them fail (red).
  • Implement the smallest amount of code to make the tests pass (green).
  • Refactor while keeping tests green.
When a team consistently applies TDD it reduces regressions and improves long-term velocity. Claude Code can accelerate the mechanical, repetitive parts of TDD such as generating comprehensive test cases.

Requirements and test expectations

  • Every conversion function accepts a single numeric argument (int or float) and returns a float.
  • Note: in Python, bool is a subclass of int and will satisfy isinstance(value, (int, float)). If you need to reject booleans (True/False), adjust the input validation accordingly.
  • If a non-numeric value is passed, the functions must raise TypeError.
  • Tests should cover: integers, floats, zero, negative values, and invalid inputs.
  • Use pytest.approx() in tests where floating-point precision matters.

Conversion formulas and constants

Below is a concise table of the functions, formulas, and precise conversion factors used by the tests and implementation.
FunctionFormula / FactorDescription
miles_to_kilometers(miles)km = miles * 1.609341 mile = 1.60934 kilometers
kilometers_to_miles(km)miles = km * 0.6213711 km ≈ 0.621371 miles
gallons_to_liters(gallons)L = gallons * 3.7854117841 US gallon = 3.785411784 liters
liters_to_gallons(liters)gal = liters * 0.26417205235814841 L ≈ 0.2641720523581484 US gallons
pounds_to_kilograms(pounds)kg = pounds * 0.453592371 lb = 0.45359237 kg
kilograms_to_pounds(kg)lb = kg * 2.20462262184877571 kg ≈ 2.2046226218487757 lb
fahrenheit_to_celsius(F)C = (F - 32) * 5/9Fahrenheit → Celsius
celsius_to_fahrenheit(C)F = C * 9/5 + 32Celsius → Fahrenheit

Using Claude Code to generate tests

Workflow used:
  1. Craft a clear prompt describing required test coverage for converter.py.
  2. Ask Claude Code to generate a comprehensive pytest suite (test_converter.py).
  3. Run pytest to see failing tests (expected first red).
  4. Implement converter.py to satisfy tests, iterate until green.
The generated test suite covers:
  • Correctness for integers and floats.
  • Zero input scenarios.
  • Negative value tests.
  • TypeError tests for non-numeric inputs.
  • Use of pytest.approx() for floating-point comparisons.
Example test file header and organization (representative):
# test_converter.py (representative header)
import pytest
from converter import (
    miles_to_kilometers,
    kilometers_to_miles,
    gallons_to_liters,
    liters_to_gallons,
    pounds_to_kilograms,
    kilograms_to_pounds,
    fahrenheit_to_celsius,
    celsius_to_fahrenheit
)

class TestDistanceConversions:
    """Test distance conversion functions"""
    # ... test methods ...

class TestVolumeConversions:
    """Test volume conversion functions"""
    # ... test methods ...

class TestMassConversions:
    """Test mass conversion functions"""
    # ... test methods ...

class TestTemperatureConversions:
    """Test temperature conversion functions"""
    # ... test methods ...
The test file was edited in VS Code; when saving the test file the editor prompted to write changes:
A screenshot of Visual Studio Code with a text file open containing instructions to create pytest tests for a Python unit-converter (test_converter.py). The integrated terminal shows a prompt asking whether to save the edits to test_converter.py.

Running the tests (first run)

Before implementing converter.py, running pytest fails at collection:
$ python3 -m pytest -q
ImportError while importing test module 'test_converter.py'
E   ModuleNotFoundError: No module named 'converter'
This is the expected “red” step in the red/green/refactor cycle. Now implement the module to satisfy the tests.

Implementing converter.py

Implementation goals:
  • Validate inputs and raise TypeError for non-numeric values.
  • Use correct formulas and precise conversion constants.
  • Always return a float.
A concise and correct implementation:
def _ensure_numeric(value):
    """Internal helper to validate numeric inputs."""
    if not isinstance(value, (int, float)):
        raise TypeError("Input was not a numeric value")


def miles_to_kilometers(miles):
    """Converts miles to kilometers."""
    _ensure_numeric(miles)
    return float(miles) * 1.60934


def kilometers_to_miles(km):
    """Converts kilometers to miles."""
    _ensure_numeric(km)
    return float(km) * 0.621371


def gallons_to_liters(gallons):
    """Converts US gallons to liters."""
    _ensure_numeric(gallons)
    # Precise US gallon to liter factor
    return float(gallons) * 3.785411784


def liters_to_gallons(liters):
    """Converts liters to US gallons."""
    _ensure_numeric(liters)
    return float(liters) * 0.2641720523581484


def pounds_to_kilograms(pounds):
    """Converts pounds to kilograms."""
    _ensure_numeric(pounds)
    return float(pounds) * 0.45359237


def kilograms_to_pounds(kg):
    """Converts kilograms to pounds."""
    _ensure_numeric(kg)
    return float(kg) * 2.2046226218487757


def fahrenheit_to_celsius(fahrenheit):
    """Converts degrees Fahrenheit to Celsius."""
    _ensure_numeric(fahrenheit)
    return (float(fahrenheit) - 32.0) * (5.0 / 9.0)


def celsius_to_fahrenheit(celsius):
    """Converts degrees Celsius to Fahrenheit."""
    _ensure_numeric(celsius)
    return float(celsius) * (9.0 / 5.0) + 32.0

Iterating with pytest

  • Re-run pytest after implementing the module and fix any failures.
  • Floating-point mismatches can occur between constants used in tests and implementation. Tests should use pytest.approx() to tolerate reasonable differences.
  • If a persistent mismatch remains, prefer improving implementation precision rather than loosening tests unless the tests are incorrect.
Example successful test run:
$ python3 -m pytest -q
........................................  # all tests pass (representative)
40 passed in 0.12s
LLMs (such as Claude Code) are powerful for generating comprehensive, mechanical test suites and scaffolding implementations. Always perform human review and iterative testing—LLM outputs are excellent starting points but may need adjustments for precision, edge cases, and integration context.

Summary and recommendations

  • TDD gives you a precise specification and reduces regressions.
  • Use Claude Code to speed up repetitive tasks like generating extensive test cases.
  • Always run and iterate on tests locally: LLMs may need guidance around precision and edge cases.
  • Keep tests deterministic and specific; use pytest.approx() for floating-point assertions with reasonable tolerances.
  • Store the test prompts and generated tests in your repository as a reusable starting point for TDD experiments.
Further reading and references:

Watch Video