Pytest Fixtures and Conftest.py: Overriding Session-Scoped State Across Directory Hierarchies
0 reputation · 18 Apr 2022, 01:53 UTC
0 reputation · 18 Apr 2022, 01:53 UTC
Pytest utilizes a dependency injection pattern where fixtures are defined in conftest.py files to share setup and teardown logic across modules. When using session-scoped fixtures, the lifecycle is intended to persist across the entire test suite execution.
A design challenge arises when a project structure requires a global session fixture in the root directory, but specific sub-directories require a modified implementation of that same fixture to handle localized environment constraints.
While pytest allows overriding fixtures in nested conftest.py files, the interaction between the session scope and the directory hierarchy can create uncertainty regarding fixture instantiation and teardown order.
Overriding a session-scoped fixture in a sub-directory does not create a new instance per test. The overridden fixture remains session-scoped, so pytest creates exactly one instance of that specific fixture definition per test session—the first time any test in that sub-directory requests it. Tests outside the sub-directory continue to receive the root fixture, potentially resulting in two separate session-scoped instances if both fixture definitions are exercised during the same run.
Teardown occurs after the entire test session finishes, in reverse order of first creation. Each fixture definition (root and overridden) is torn down exactly once, regardless of how many tests use it. Overriding does not alter this global teardown sequence.
Pytest resolves fixtures by walking the directory hierarchy from the test file upward. When a sub-directory conftest.py defines a fixture with the same name as a parent, that definition shadows the parent for all tests collected under that sub-tree. The two fixtures are completely independent—different objects, different setup/teardown calls, different lifecycles.
Session-scoped fixtures are torn down in reverse order of their first setup. If the root fixture sets up first (because a root test runs first), its teardown runs last. If a sub-directory test runs first and triggers the overridden fixture setup, that fixture tears down last. The directory hierarchy does not dictate teardown order—execution order does.
conftest.py at project root with a session fixture printing SETUP_ROOT/TEARDOWN_ROOT.subdir/conftest.py overriding the same fixture name, printing SETUP_SUB/TEARDOWN_SUB.subdir/ that request the fixture.pytest -s and observe:
SETUP_* message appears exactly onceSETUP_SUB/TEARDOWN_SUBSETUP_ROOT/TEARDOWN_ROOTIf you need one shared resource across the entire suite with localized configuration, avoid overriding. Instead, make the root fixture configurable (e.g., via a session-scoped config fixture or environment variables) so sub-directories influence behavior without creating a second instance. Override only when you genuinely need independent resources (e.g., separate database connections, distinct temp directories).
Are both the root and overridden fixtures actually used in the same test session? If your test suite only runs tests from the sub-directory, the root fixture is never instantiated and the question of dual instances/teardown order is moot.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.