Fixture Lifecycle

Purpose

This subtopic addresses the complete lifecycle management of fixtures within the pytest framework. Unlike the broader fixture system that encompasses scoping, parametrization, and injection, the fixture lifecycle focuses specifically on how fixture instances are created, cached, reused, and properly torn down (finalized) during test execution. It ensures that fixtures are instantiated only once per their defined scope and that any associated teardown code is executed correctly after tests complete or when fixture instances are no longer valid.

Functionality

The lifecycle management of fixtures revolves around several key workflows:

Fixture Execution and Caching

Setup and Teardown

Scope and Dependency Awareness

Error Handling

Key Classes and Methods

Example Code Snippet

def execute(self, request: SubRequest) -> FixtureValue:
    # Check cache and dependencies
    if self.cached_result is not None:
        # Return cached value if parameters match
        ...
    # Setup dependent fixtures
    ...
    # Execute fixture function and cache the result
    result = request.node.ihook.pytest_fixture_setup(fixturedef=self, request=request)
    # Register finalizer for teardown
    request.node.addfinalizer(functools.partial(self.finish, request=request))
    return result

This method coordinates the entire lifecycle for a single fixture invocation.

Relationship to Parent Topic

The parent topic, *Fixture Management*, provides the overall framework for defining, requesting, and injecting fixtures with features like parametrization and dependency resolution. *Fixture Lifecycle* is a critical subcomponent focused on the temporal aspect — how fixtures are instantiated, reused, and cleaned up during test runs.

Together, these subtopics form a cohesive fixture system that is powerful, efficient, and reliable.

Diagram

The following flowchart visualizes the core process of fixture lifecycle management during test execution:

flowchart TD
    A[Test Requests Fixture] --> B[Resolve FixtureDef & Scope]
    B --> C{Is Fixture Cached for Scope & Params?}
    C -->|Yes| D[Return Cached Fixture Value]
    C -->|No| E[Setup Dependent Fixtures]
    E --> F[Execute Fixture Function]
    F --> G{Is Generator Fixture?}
    G -->|Yes| H[Run Setup Part (before yield)]
    G -->|No| I[Run Fixture Function Normally]
    H --> J[Cache Yielded Value]
    I --> J[Cache Return Value]
    J --> K[Register Finalizer for Teardown]
    K --> L[Return Fixture Value]

    subgraph Teardown Phase
        M[After Tests or Scope Ends] --> N[Call Registered Finalizers]
        N --> O[Clear Cached Result]
    end

    L --> M

This flowchart highlights the decision points and major steps in setting up, caching, and finalizing fixtures, encapsulating the lifecycle that supports pytest's flexible fixture system.