Every Python project eventually needs the same test infrastructure. You write conftest.py from scratch, reach for the same Hypothesis patterns, copy async fixture code from a Stack Overflow answer that's three major versions out of date.
I've done this enough times that I started keeping the files. This week I packaged them up.
The Python Testing Toolkit is available now on Gumroad: four production-ready Python files — conftest_production.py, hypothesis_strategies.py, async_test_patterns.py, and parametrize_factories.py. $49, one-time download, MIT license.
Here's exactly what's in each one.
conftest_production.py — the conftest you'd write if you had eight hours
Most conftest.py tutorials show you database fixtures or HTTP mocking. Almost none show both in a form that composes cleanly with async tests, FastAPI dependency overrides, and environment variable isolation.
This file handles all of it:
# Transaction rollback per test — no cleanup needed
def test_creates_user(db_session):
user = User(name="Alice", email="[email protected]")
db_session.add(user)
db_session.flush()
result = db_session.get(User, user.id)
assert result.name == "Alice"
# rolls back automatically — nothing persists between tests
# FastAPI dependency overrides without boilerplate
def test_endpoint_with_mock_service(client_with_override):
mock_service = MagicMock(return_value={"id": 1, "name": "Alice"})
with client_with_override({get_user_service: lambda: mock_service}) as c:
response = c.get("/users/1")
assert response.status_code == 200
# Environment variables that reset between tests
def test_feature_flag(env_override):
with env_override(ENABLE_BETA="true", DATABASE_URL="sqlite:///:memory:"):
result = function_that_reads_env()
assert result.used_beta_path
# ENABLE_BETA is unset again here — no state leaks
The database fixture defaults to SQLite with transaction rollback per test. Swap to Postgres by setting a DATABASE_URL environment variable — the fixture handles both without modification. HTTP mocking covers both httpx (via respx) and requests (via responses) because most projects have both.
Drop this into your project root as conftest.py. pytest finds everything automatically.
hypothesis_strategies.py — stop using .text() for emails
Hypothesis ships with text(), integers(), floats(), dates(). These are correct types for testing algorithms. They're useless for testing application code that expects email addresses, usernames, financial amounts, or URL paths.
When Hypothesis generates "\x00\x7f\ud800" as a test email, your validator fails for the wrong reason. You fix the test to exclude those cases, not the code. The test becomes meaningless.
This file has 30+ strategies for the types that appear in every domain:
from hypothesis import given
from hypothesis_strategies import emails, usernames, monetary_amounts
@given(email=emails(), username=usernames())
def test_user_registration(email, username):
user = User.create(email=email, username=username)
assert user.email == email.lower()
assert len(user.username) >= 3
from decimal import Decimal
from hypothesis_strategies import monetary_amounts, order_data
@given(amount=monetary_amounts(min_value=Decimal("0.01"), max_value=Decimal("10000.00")))
def test_payment_processing(amount):
result = process_payment(amount)
assert result.status == "success"
assert result.charged == amount
# Generate complete valid payloads in one line
@given(registration=user_registration_data())
def test_registration_endpoint(client, registration):
response = client.post("/register", json=registration)
# Should be 201 (success) or 422 (validation error), never 500
assert response.status_code in (201, 422)
The user_registration_data() strategy composes emails(), usernames(), and optionally phone_numbers_e164() into a valid registration dict. order_data() generates line items with Decimal amounts that sum correctly. Each strategy accepts parameters for tightening bounds when you need to test specific edge cases.
The covers that.
Not Django-specific. The HTTP mocking and parametrize factories work anywhere. The database and async fixtures are FastAPI-oriented. The Hypothesis strategies are framework-independent.
Not a subscription, SaaS integration, or CI dashboard. Four Python files. Download once, use in any project, forever.
Getting it
drops in September — the async_test_patterns.py file from this toolkit is the implementation behind the patterns in that article.
Questions? Drop them in the comments or reach me at series.
SOCIAL SHARE CARD GENERATOR