pytest
01 / 02

Fixtures & Test Basics

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-failed

Fixtures

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_client

conftest.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