Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Pytest fixtures: isolated files and parameterized rejection tests

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A pytest fixture supplies test-owned setup and cleanup so cases can exercise an operation without sharing accidental state.

Download Python source kit

Operation contract

The fixture creates a tiny test module in an owned temporary directory and runs pytest in a child interpreter. The tmp_path fixture gives the accepted-input test its own file. Parameterized rejection cases cover a negative quantity, a boolean and text. The subprocess checks the exit code rather than depending on pytest’s version-specific progress text.

Failure and ownership boundary

This lesson disables automatic third-party plugin loading in the child environment and names its test file explicitly. A passing fixture does not prove every caller or deployment path is safe. Test isolation must extend to databases, clocks and network collaborators when those enter the operation. Python unittest.mock: inject a collaborator failure before publication and Python unittest: test rejected input and preserve state after failure illustrate alternative test boundaries.

Tested environment

Dependency check: this program was executed on CPython 3.14.6 with pytest==9.1.1. Install these versions in a separate virtual environment. The download includes the recorded environment snapshot; no third-party package is part of the website runtime.

Working program

python
from pathlib import Path
import os
import subprocess
import sys
import tempfile

TEST_SOURCE = """import pytest

def accepted_quantity(value):
    if type(value) is not int or not 0 <= value <= 8:
        raise ValueError('quantity rejected')
    return value

def test_owned_file(tmp_path):
    manifest = tmp_path / 'quantity.txt'
    manifest.write_text('3', encoding='utf-8')
    assert accepted_quantity(int(manifest.read_text(encoding='utf-8'))) == 3

@pytest.mark.parametrize('quantity', [-1, True, '3'])
def test_rejected_quantity(quantity):
    with pytest.raises(ValueError):
        accepted_quantity(quantity)
"""
with tempfile.TemporaryDirectory() as directory:
    target = Path(directory) / "test_quantity.py"
    target.write_text(TEST_SOURCE, encoding="utf-8")
    environment = dict(os.environ, PYTEST_DISABLE_PLUGIN_AUTOLOAD="1")
    result = subprocess.run([sys.executable, "-I", "-m", "pytest", "-q", str(target)],
                            cwd=directory, env=environment, capture_output=True, text=True, timeout=10)
    if result.returncode:
        raise RuntimeError("owned pytest cases failed")
print("four owned pytest cases passed")

Output

Output
four owned pytest cases passed

Costs and limits

The four cases perform bounded local work. Interpreter startup and test collection dominate this small run; no speed comparison with unittest is claimed. Real integration suites must budget their external resources separately.

Common Mistakes

  • Do not let tests share mutable files without explicit ownership.
  • Assert the operation’s contract rather than copying its implementation into the expected result.

Connected lessons

Python unittest: test rejected input and preserve state after failure, Python unittest.mock: inject a collaborator failure before publication, Python input exercise: accept an explicit integer grammar.

Follow the related contract

Hypothesis property tests: compare generated cases with an independent contract, Coverage.py branch coverage: execution paths are not correctness assertions.

Trace the related workflow

Python IsolatedAsyncioTestCase: own async setup and cleanup per test.

python
pytest-fixtures
Storage details