Fixtures & Test Basics
Writing Tests
# test_calculator.py — pytest auto-discovers test_*.py / *_test.py, functions named test_*
def test_addition():
assert 1 + 1 == 2 # plain assert — pytest rewrites it to show a diff on failure
def test_division_by_zero():
with pytest.raises(ZeroDivisionError):
1 / 0
# Class-based grouping — no TestCase base class needed
class TestCalculator:
def test_multiply(self):
assert 3 * 4 == 12
def test_subtract(self):
assert 5 - 2 == 3
# Run: pytest — everything
# Run: pytest test_calculator.py — one file
# Run: pytest test_calculator.py::test_addition — one test
# Run: pytest -k "addition" — name substring match
# Run: pytest -v — verbose, one line per test
# Run: pytest -x — stop at first failure
# Run: pytest --lf — rerun only last-failedFixtures
import pytest
@pytest.fixture
def sample_user():
return {'name': 'Alice', 'email': 'alice@example.com'}
def test_user_email(sample_user):
# Just name the fixture as a parameter — pytest resolves and injects it
assert sample_user['email'].endswith('@example.com')
# Setup + teardown via yield
@pytest.fixture
def db_connection():
conn = connect_to_test_db()
yield conn # value handed to the test
conn.close() # runs after the test, even if it failed
# Scopes: function (default) < class < module < package < session
@pytest.fixture(scope='session')
def api_client():
return build_expensive_client() # created once for the whole test run
# autouse — runs for every test in scope without being named as a parameter
@pytest.fixture(autouse=True)
def reset_global_state():
yield
global_cache.clear()
# Fixtures composing other fixtures
@pytest.fixture
def authenticated_client(api_client, sample_user):
api_client.login(sample_user['email'])
return api_clientconftest.py & Shared Fixtures
# conftest.py — auto-discovered by pytest, no import needed.
# Fixtures defined here are visible to every test in this directory and below.
import pytest
@pytest.fixture
def client():
from myapp import create_app
app = create_app(testing=True)
return app.test_client()
# Register custom markers to avoid "unknown marker" warnings
# pytest.ini / pyproject.toml:
# [tool.pytest.ini_options]
# markers = [
# "slow: marks tests as slow",
# "integration: marks integration tests",
# ]
# Usage + filtering:
# @pytest.mark.slow
# def test_big_import(): ...
#
# pytest -m "not slow" — skip slow tests
# pytest -m "slow and not integration"Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free