pytest: Python Testing Framework
pytest is a mature, feature-rich testing framework for Python that simplifies test writing and execution through a clear, concise syntax. Unlike Python’s built-in unittest module, pytest minimizes boilerplate and offers powerful fixture capabilities, parameterized testing, and a comprehensive plugin ecosystem.
pytest is the standard choice for most Python testing, from small scripts to large applications. Its assert-based syntax requires less code than unittest, and its fixture system scales well as projects grow. The main reasons to prefer unittest over pytest are maintaining a codebase already committed to unittest conventions or working in an environment where third-party packages are restricted.
For step-by-step guides on specific pytest features, see How to parameterize tests with pytest, How to run tests in parallel with pytest-xdist, and How to measure code coverage with pytest-cov.
When to use pytest
Use pytest for any Python project that needs automated tests. Its low-boilerplate syntax and fixture system make it the right default for unit tests, integration tests, and end-to-end tests alike. Prefer pytest over unittest unless the project already uses unittest conventions throughout or third-party packages cannot be installed. For multi-version test automation, pair pytest with tox or nox.
Core Features
Test Discovery and Execution
- Automatic discovery of test modules, functions, and methods following naming conventions
- Simple assertion syntax using Python’s built-in
assert - Detailed failure reports with intelligent introspection and value comparison
- Flexible test selection via command-line options, markers, and path specifications
- Parallel test execution for faster test runs
Fixtures
Fixtures provide a modular way to manage test dependencies and setup/teardown:
@pytest.fixture
def api_client():
client = APIClient()
yield client
client.close()
def test_api_call(api_client):
# The fixture is automatically injected
response = api_client.get_data()
assert response.status_code == 200Fixtures can be scoped to function, class, module, or session levels.
Class-scoped fixtures defined as instance methods without @classmethod are deprecated as of pytest 9.1 and will be removed in pytest 10; apply @classmethod to any such fixtures to remove the warning.
When using --doctest-modules, autouse fixtures with module, package, or session scope defined directly in a test module (not in conftest.py) may run twice: once for the Module collector and once for DoctestModule. Move such fixtures to conftest.py to avoid duplicate execution.
Parameterization
Tests can be run with multiple sets of inputs:
@pytest.mark.parametrize("input,expected", [
(1, 1),
(2, 4),
(3, 9),
(4, 16),
])
def test_square(input, expected):
assert input * input == expectedPassing generators or iterators as argvalues is deprecated as of pytest 9.1 because they are exhausted after the first collection pass, silently skipping tests on repeated runs. Use a list or tuple instead.
Command-Line Interface
# Run all tests
pytest
# Run tests in a specific file
pytest test_file.py
# Run a specific test
pytest test_file.py::test_function
# Run tests matching a pattern
pytest -k "pattern"
# Run tests with a specific marker
pytest -m slow
# Fail when accumulated warnings exceed a threshold
pytest --max-warnings=5Configuration
Pytest reads settings from pyproject.toml under [tool.pytest.ini_options]:
[tool.pytest.ini_options]
# Fail the run when warning count exceeds this threshold
max_warnings = 5
# Render string equality failures as "Left:"/"Right:" blocks instead of ndiff output
assertion_text_diff_style = "split"Pros
- Minimal boilerplate compared to unittest
- Powerful fixture system for dependency injection
- Extensive plugin ecosystem
- Detailed error reporting
- Compatible with other testing tools
Cons
- Learning curve for advanced features
- Plugin dependencies can complicate maintenance
- Fixture complexity can grow in large projects
- Some patterns differ from unittest paradigms
Learn More
- Setting up testing with pytest and uv (Tutorial)
- How to run tests using uv
- How to test against multiple Python versions using uv
- How to fix common pytest errors with uv
- How to parameterize tests with pytest
- How to run tests in parallel with pytest-xdist
- How to measure code coverage with pytest-cov
- How to configure Cursor for pytest
- How to configure Claude Code to run your pytest suite
- Essential pytest plugins for reliable, fast test suites
- tox and nox for multi-version test automation
- pytest Documentation
- Plugin Directory
- Best Practices