pytest Testing Configuration Reference

Type: Software Reference Confidence: 0.94 Sources: 7 Verified: 2026-02-28 Freshness: 2026-02-28

TL;DR

Constraints

Quick Reference

SettingLocationPurpose
[tool.pytest.ini_options]pyproject.tomlMain config section
testpathspyproject.tomlTest directories
pythonpathpyproject.tomlsys.path additions
addoptspyproject.tomlDefault CLI options
markerspyproject.tomlRegister custom markers
conftest.pytest directoryShared fixtures
@pytest.fixtureconftest/testReusable test setup
@pytest.mark.parametrizetest functionMultiple inputs
--covCLICoverage (pytest-cov)
-n autoCLIParallel (pytest-xdist)

Decision Tree

START
├── New project? → src layout + pyproject.toml
├── Testing async? → pytest-asyncio, asyncio_mode = "auto"
├── Need parallel? → pytest-xdist, -n auto
├── Need coverage? → pytest-cov, --cov
└── DEFAULT → pyproject.toml + conftest.py + pytest-cov

Step-by-Step Guide

1. Install pytest and plugins

[src1]

pip install pytest pytest-cov pytest-mock pytest-xdist
# For async: pip install pytest-asyncio

2. Configure pyproject.toml

[src1]

[tool.pytest.ini_options]
minversion = "8.0"
testpaths = ["tests"]
pythonpath = ["src"]
addopts = ["-ra", "--strict-markers", "-v", "--tb=short"]
markers = [
    "slow: marks tests as slow",
    "integration: marks integration tests",
]

3. Create conftest.py

[src2]

import pytest

@pytest.fixture
def sample_data():
    return {"name": "test", "value": 42}

@pytest.fixture(scope="session")
def db_connection():
    conn = create_connection()
    yield conn
    conn.close()

4. Write parametrized tests

[src3]

@pytest.mark.parametrize("price,expected", [(100, 90), (200, 180), (0, 0)])
def test_calculate_discount(price, expected):
    assert calculate_discount(price, discount=0.10) == expected

5. Configure coverage

[tool.coverage.run]
source = ["src"]
branch = true

[tool.coverage.report]
fail_under = 80
show_missing = true

Code Examples

Complete pyproject.toml

[tool.pytest.ini_options]
minversion = "8.0"
testpaths = ["tests"]
pythonpath = ["src"]
addopts = ["-ra", "--strict-markers", "-v", "--cov=src", "--cov-report=term-missing", "--timeout=30"]
markers = ["slow: slow tests", "integration: integration tests", "e2e: end-to-end tests"]
asyncio_mode = "auto"

[tool.coverage.run]
source = ["src"]
branch = true
omit = ["*/tests/*"]

[tool.coverage.report]
fail_under = 80
show_missing = true
exclude_lines = ["pragma: no cover", "if __name__ == .__main__.", "if TYPE_CHECKING:"]

Advanced conftest.py

import pytest

@pytest.fixture
def make_user():
    def _make_user(name="test_user", role="viewer"):
        return {"name": name, "role": role}
    return _make_user

@pytest.fixture(scope="session")
def database():
    db = setup_test_database()
    yield db
    teardown_test_database(db)

@pytest.fixture(autouse=True)
def clean_state(database):
    yield
    database.rollback()

Parametrize with IDs

@pytest.mark.parametrize("input_data,expected", [
    pytest.param({"key": "value"}, True, id="valid-dict"),
    pytest.param({}, False, id="empty-dict"),
    pytest.param(None, False, id="none-input"),
])
def test_validate_data(input_data, expected):
    assert validate(input_data) == expected

Anti-Patterns

Wrong: Importing conftest.py directly

# ❌ BAD — conftest.py is auto-discovered
from tests.conftest import sample_data

Correct: Request fixtures as parameters

# ✅ GOOD — pytest injects fixtures automatically
def test_something(sample_data):
    assert sample_data["name"] == "test"

Wrong: Higher-scoped fixture depending on lower-scoped

# ❌ BAD — ScopeMismatch error
@pytest.fixture(scope="session")
def database(tmp_path):  # tmp_path is function-scoped!

Correct: Use session-compatible equivalents

# ✅ GOOD — tmp_path_factory is session-scoped
@pytest.fixture(scope="session")
def database(tmp_path_factory):
    path = tmp_path_factory.mktemp("data")
    return create_db(path)

Wrong: Misspelling parametrize

# ❌ BAD — silently ignored
@pytest.mark.parameterize("x", [1, 2, 3])  # Wrong!

Correct: British spelling without second 'e'

# ✅ GOOD
@pytest.mark.parametrize("x", [1, 2, 3])

Common Pitfalls

Diagnostic Commands

# Discover tests without running
pytest --collect-only

# Show fixtures
pytest --fixtures

# Run by keyword
pytest -k "test_auth"

# Run by marker
pytest -m "not slow"

# Show durations
pytest --durations=10

# HTML coverage
pytest --cov=src --cov-report=html

Version History & Compatibility

VersionStatusBreaking ChangesMigration Notes
pytest 8.xCurrentCollection changes, warns(None) deprecatedUse recwarn fixture
pytest 7.xMaintenancepythonpath addedBest upgrade from 6.x
pytest 6.xEOLpyproject.toml supportMigrate from pytest.ini

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Any Python projectJavaScript/TypeScriptJest or Vitest
Complex fixture graphsMinimal, no-dep testingunittest (stdlib)
Parametrized testingLoad testinglocust or k6

Important Caveats

Related Units