Skip to content

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.

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 == 200

Fixtures can be scoped to function, class, module, or session levels.

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 == expected

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

# Generate coverage report
pytest --cov=mypackage

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

Last updated on

Please submit corrections and feedback...