python-testing
Python Testing Patterns
Comprehensive testing strategies for Python applications using pytest, TDD methodology, and best practices.
When to Use
- Writing new Python code (follow TDD: red, green, refactor)
- Designing test suites for Python projects
- Reviewing Python test coverage
- Setting up testing infrastructure
- Need guidance on fixtures, mocking, or parametrization
TDD Cycle
Always follow the Red → Green → Refactor cycle:
- RED: Write a failing test for the desired behavior
- GREEN: Write minimal code to make the test pass
- REFACTOR: Improve code while keeping tests green
Quick Start
import pytest
# Basic test
def test_addition():
assert 2 + 2 == 4
# Test with fixture
@pytest.fixture
def sample_data():
return {"name": "Alice", "age": 30}
def test_sample_data(sample_data):
assert sample_data["name"] == "Alice"
# Parametrized test
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("world", "WORLD"),
])
def test_uppercase(input, expected):
assert input.upper() == expected
# Exception testing
def test_divide_by_zero():
with pytest.raises(ZeroDivisionError):
_ = 1 / 0
Core Topics
Fixtures
Setup and teardown for tests, sharing data, and scopes (function, module, session).
Details: references/fixtures.md
Parametrization
Running tests with multiple inputs using @pytest.mark.parametrize.
Details: references/parametrization.md
Mocking and Patching
Using unittest.mock to mock external dependencies and API calls.
Details: references/mocking.md
Markers and Test Selection
Custom markers (@pytest.mark.slow) and selective test execution.
Details: references/markers.md
Async Testing
Testing async functions with pytest-asyncio.
Details: references/async_testing.md
Test Organization
Directory structure, conftest.py, and grouping related tests.
Details: references/test_organization.md
Quick Reference
| Pattern | Usage |
|---|---|
pytest.raises() |
Test expected exceptions |
@pytest.fixture() |
Create reusable test fixtures |
@pytest.mark.parametrize() |
Run tests with multiple inputs |
@pytest.mark.slow |
Mark slow tests |
pytest -m "not slow" |
Skip slow tests |
@patch() |
Mock functions and classes |
tmp_path fixture |
Automatic temp directory |
pytest --cov |
Generate coverage report |
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=mypackage --cov-report=html
# Run only fast tests
pytest -m "not slow"
# Run with verbose output
pytest -v
# Run until first failure
pytest -x
# Run last failed tests
pytest --lf
Best Practices
DO:
- Follow TDD (write tests before code)
- Test one thing per test
- Use descriptive test names
- Use fixtures to eliminate duplication
- Mock external dependencies
- Aim for 80%+ coverage
- Keep tests fast
DON'T:
- Test implementation details
- Use complex conditionals in tests
- Share state between tests
- Catch exceptions in tests (use
pytest.raises) - Write tests that are too brittle
Details: references/best_practices.md
Common Patterns
API Endpoint Testing
@pytest.fixture
def client():
app = create_app(testing=True)
return app.test_client()
def test_get_user(client):
response = client.get("/api/users/1")
assert response.status_code == 200
Database Testing
@pytest.fixture
def db_session():
session = Session(bind=engine)
session.begin_nested()
yield session
session.rollback()
session.close()
More patterns: references/common_patterns.md