Testing
Testing Python with pytest -- fixtures, parametrization, async tests, mocking external services, and shared conftest fixtures
Testing
pytest is the de facto standard for testing Python. Its fixture system provides clean dependency injection, parametrization gives you table-driven tests, and the ecosystem handles async and mocking with minimal ceremony.
Testing with pytest
import pytest
from unittest.mock import AsyncMock, patch
# Fixtures for dependency injection
@pytest.fixture
def db_session():
session = create_test_session()
yield session
session.rollback()
# Parametrized tests (like Go's table-driven tests)
@pytest.mark.parametrize("input,expected", [
("$100.00", 10000),
("$0.50", 50),
("-$25.00", -2500),
])
def test_parse_amount(input: str, expected: int):
assert parse_amount(input) == expected
# Async test
@pytest.mark.asyncio
async def test_fetch_user(db_session):
user = await create_user(db_session, name="Alice")
fetched = await get_user(db_session, user.id)
assert fetched.name == "Alice"
# Mocking external services
async def test_payment_processing():
with patch("app.services.stripe_client") as mock_stripe:
mock_stripe.charge = AsyncMock(return_value={"id": "ch_123"})
result = await process_payment(amount=1000, currency="nzd")
assert result.stripe_id == "ch_123"
mock_stripe.charge.assert_called_once()
# conftest.py -- shared fixtures across test modules
@pytest.fixture(scope="session")
def app():
return create_app(testing=True)
@pytest.fixture(autouse=True)
def reset_db(db_session):
yield
db_session.rollback()