markers.rst

Overview

This documentation file provides an extensive guide on using **pytest markers**—a powerful feature in the pytest testing framework that allows users to add metadata and selectively run tests based on custom or built-in markers.

Markers enable flexible test selection, grouping, and conditional execution by associating tests with labels or expressions. This file explains how to apply markers, register custom markers, use marker expressions for test selection, and advanced usage such as scoped marking, parameterized test marking, and plugin-defined markers.

It also covers practical examples, command line usages, and best practices for marker management in pytest test suites.


Detailed Descriptions

Key Concepts


Sections & Examples

Marking Test Functions and Selecting Tests

You can mark test functions by decorating them with `@pytest.mark.`. Markers may also accept keyword arguments.

import pytest

@pytest.mark.webtest
def test_send_http():
    pass

@pytest.mark.device(serial="123")
def test_something_quick():
    pass

**Selecting tests by marker:**

**Notes:**


Selecting Tests by Node ID

Node IDs allow precise selection of tests by module, class, or method names.

Examples:

**Node ID format:**


Selecting Tests by Name with -k

The `-k` option allows substring matching (case-insensitive) on test names, marker names, parent names, and extra keywords.

Examples:

Logical operators supported: `and`, `or`, `not` with parentheses for grouping.


Registering Markers

To avoid typos and maintain clarity, markers should be registered in the pytest configuration file (`pytest.ini`):

[pytest]
markers =
    webtest: mark a test as a webtest.
    slow: mark test as slow.

You can list all registered markers with:

pytest --markers

Scoped Marking: Classes and Modules

Markers can be applied at class or module level to mark all contained tests.

Multiple markers can be applied by setting `pytestmark` to a list.


Marking Individual Parameterized Tests

With `@pytest.mark.parametrize`, you can mark individual test cases differently:

@pytest.mark.foo
@pytest.mark.parametrize(
    ("n", "expected"), 
    [
        (1, 2), 
        pytest.param(1, 3, marks=pytest.mark.bar), 
        (2, 3)
    ]
)
def test_increment(n, expected):
    assert n + 1 == expected

Here, the `foo` marker applies to all cases; `bar` applies only to the second.


Custom Marker and Command Line Option Example

A plugin can add custom markers and command line options to control test runs:

Example plugin in `conftest.py`:

import pytest

def pytest_addoption(parser):
    parser.addoption("-E", action="store", metavar="NAME",
                     help="only run tests matching the environment NAME.")

def pytest_configure(config):
    config.addinivalue_line(
        "markers", "env(name): mark test to run only on named environment"
    )

def pytest_runtest_setup(item):
    envnames = [mark.args[0] for mark in item.iter_markers(name="env")]
    if envnames and item.config.getoption("-E") not in envnames:
        pytest.skip(f"test requires env in {envnames!r}")

Usage:

pytest -E stage1

Passing Callables to Custom Markers

When passing a callable as a marker argument, use `.with_args` to avoid decorating the callable instead of passing it as an argument:

@pytest.mark.my_marker.with_args(hello_world)
def test_with_args():
    pass

Reading Multiple Marker Applications

Markers can be applied multiple times to the same test (e.g., on module, class, and function).

From plugin code, you can iterate all applied markers:

def pytest_runtest_setup(item):
    for mark in item.iter_markers(name="glob"):
        print(f"glob args={mark.args} kwargs={mark.kwargs}")

Platform-Specific Marking Example

A plugin can skip tests not matching the current platform marker:

import sys
import pytest

ALL = set("darwin linux win32".split())

def pytest_runtest_setup(item):
    supported_platforms = ALL.intersection(mark.name for mark in item.iter_markers())
    plat = sys.platform
    if supported_platforms and plat not in supported_platforms:
        pytest.skip(f"cannot run on platform {plat}")

Automatically Adding Markers Based on Test Names

Tests can be dynamically marked based on their names during collection:

def pytest_collection_modifyitems(items):
    for item in items:
        if "interface" in item.nodeid:
            item.add_marker(pytest.mark.interface)
        elif "event" in item.nodeid:
            item.add_marker(pytest.mark.event)

This allows use of `-m interface` or `-m event` to select subsets of tests.


Important Implementation Details


Interactions with Other System Components


Usage Summary Examples

# Run only tests marked 'webtest'
pytest -v -m webtest

# Run tests that have marker 'device' with serial="123"
pytest -v -m "device(serial='123')"

# Run all tests except those containing 'send_http' in their name or markers
pytest -k "not send_http" -v

# Apply marker to all tests in a module
pytestmark = pytest.mark.slow

# Parametrized test with individual marks
@pytest.mark.foo
@pytest.mark.parametrize(
    ("n", "expected"),
    [(1, 2), pytest.param(1, 3, marks=pytest.mark.bar), (2, 3)]
)
def test_increment(n, expected):
    ...

Mermaid Diagram: Marker Usage Structure

The file is primarily documentation with no classes or functions defined. It revolves around pytest markers and their usage patterns.

The following flowchart illustrates the relationships between core concepts and usage workflows described:

flowchart TD
    A[Define Markers] --> B[Mark Test Functions / Classes / Modules]
    B --> C[Run Tests with Marker Selection (-m)]
    B --> D[Run Tests with Name Selection (-k)]
    B --> E[Parameterized Tests with Individual Marks]
    B --> F[Custom Markers via Plugins]
    F --> G[Add Command Line Options]
    F --> H[Add Marker Behavior in Hooks]
    C --> I[Test Collection Filters Tests by Marker Expression]
    D --> J[Substring Match on Test Names and Markers]
    I --> K[Selected Tests Run]
    J --> K
    H --> K

Summary

This file is a comprehensive guide on pytest markers, illustrating:

It serves as an essential reference for pytest users to leverage markers for flexible, maintainable, and scalable test suites.


End of Documentation for markers.rst