special.rst

Overview

This file documents a pytest session-scoped fixture example that demonstrates how to access and manipulate all collected test items before any tests run. The key functionality is embodied in a fixture named `callattr_ahead_of_alltests`, which scans all collected test classes in the test session and invokes a class-level method named `callme` if defined. This enables setup or initialization logic to be executed once per test class ahead of the test execution, regardless of the test framework used (native pytest or unittest).

Such a fixture is useful for performing preparatory actions or side effects related to test classes before any of their test methods run, enhancing test orchestration beyond just individual test setups.

Detailed Explanation

Fixture: callattr_ahead_of_alltests

@pytest.fixture(scope="session", autouse=True)
def callattr_ahead_of_alltests(request):
    print("callattr_ahead_of_alltests called")
    seen = {None}
    session = request.node
    for item in session.items:
        cls = item.getparent(pytest.Class)
        if cls not in seen:
            if hasattr(cls.obj, "callme"):
                cls.obj.callme()
            seen.add(cls)

Test Classes Defining callme

Example test classes illustrating the use of this fixture:

class TestHello:
    @classmethod
    def callme(cls):
        print("callme called!")

    def test_method1(self):
        print("test_method1 called")

    def test_method2(self):
        print("test_method2 called")


class TestOther:
    @classmethod
    def callme(cls):
        print("callme other called")

    def test_other(self):
        print("test other")


import unittest

class SomeTest(unittest.TestCase):
    @classmethod
    def callme(cls):
        print("SomeTest callme called")

    def test_unit1(self):
        print("test_unit1 method called")

Important Implementation Details

Interactions with Other System Parts

Example pytest output when running test_module.py without output capture:

$ pytest -q -s test_module.py
callattr_ahead_of_alltests called
callme called!
callme other called
SomeTest callme called
test_method1 called
.test_method2 called
.test other
.test_unit1 method called
.
4 passed in 0.12s

Mermaid Diagram: Structure of callattr_ahead_of_alltests Fixture

flowchart TD
    A[Start: Test Session Begins]
    B[callattr_ahead_of_alltests Fixture Invoked]
    C[Get session node from request]
    D[Iterate over session.items (all test items)]
    E[For each item, get parent test class]
    F{Has this class been processed?}
    G{Does class define 'callme'?}
    H[Call cls.obj.callme()]
    I[Add class to seen set]
    J[Continue iteration]
    K[Fixture ends, tests proceed]

    A --> B --> C --> D --> E --> F
    F -- No --> G
    F -- Yes --> J
    G -- Yes --> H --> I --> J
    G -- No --> I --> J
    J --> D
    D -- End of items --> K

Summary

This file provides a practical example and explanation of how to implement a pytest session-scoped fixture that accesses all collected tests and triggers class-level hooks before any test executes. It highlights pytest’s extensibility and the ability to integrate setup behavior at a granular level, supporting both pytest-native and unittest-style test classes. The documented approach is valuable for test orchestration, instrumentation, or global pre-test initialization in complex testing scenarios.