# 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 reason to run tests with unittest instead is an environment where third-party packages cannot be installed. pytest runs existing `unittest.TestCase` tests unchanged, so a codebase already written in unittest style does not require staying on unittest.

To get started with pytest, see [Setting up testing with pytest and uv](https://pydevtools.com/handbook/tutorial/setting-up-testing-with-pytest-and-uv.md) for a full walkthrough. For step-by-step guides on specific pytest features, see [How to parameterize tests with pytest](https://pydevtools.com/handbook/how-to/how-to-parameterize-tests-with-pytest.md), [How to run tests in parallel with pytest-xdist](https://pydevtools.com/handbook/how-to/how-to-run-tests-in-parallel-with-pytest-xdist.md), and [How to measure code coverage with pytest-cov](https://pydevtools.com/handbook/how-to/how-to-measure-code-coverage-with-pytest-cov.md).

## 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 third-party packages cannot be installed; pytest still runs any existing unittest tests, so a project already using unittest conventions can adopt it as the runner without a rewrite. For [multi-version test automation](https://pydevtools.com/handbook/explanation/do-you-still-need-tox-or-nox-if-you-use-uv.md), pair pytest with [tox](https://pydevtools.com/handbook/reference/tox.md) or [nox](https://pydevtools.com/handbook/reference/nox.md).

## Key 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:

```python
@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 == 200
```

Fixtures 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:

```python
@pytest.mark.parametrize("input,expected", [
    (1, 1),
    (2, 4),
    (3, 9),
    (4, 16),
])
def test_square(input, expected):
    assert input * input == expected
```

Passing 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

```bash
# 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=5
```

## Configuration

Pytest reads settings from `pyproject.toml` under `[tool.pytest.ini_options]`:

```toml
[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
