Bird
Raised Fist0
PyTesttesting~15 mins

Fixture scope with parallel tests in PyTest - Build an Automation Script

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Verify fixture scope behavior with parallel pytest tests
Preconditions (3)
Step 1: Run the tests in parallel using pytest-xdist with 2 workers
Step 2: Observe how many times the fixture setup and teardown run
Step 3: Verify that the fixture setup runs once per worker due to module scope
✅ Expected Result: Fixture setup and teardown run exactly twice in total (once per worker), and both tests pass
Automation Requirements - pytest
Assertions Needed:
Verify both test functions pass
Verify fixture setup and teardown run expected number of times (twice total)
Best Practices:
Use pytest fixtures with proper scope
Use pytest-xdist for parallel test execution
Use print statements or logging to track fixture setup/teardown
Avoid sharing state between workers
Automated Solution
PyTest
import pytest

setup_counter = 0
teardown_counter = 0

@pytest.fixture(scope='module')
def resource():
    global setup_counter
    setup_counter += 1
    print(f'Setup called {setup_counter} time(s)')
    yield
    global teardown_counter
    teardown_counter += 1
    print(f'Teardown called {teardown_counter} time(s)')


def test_one(resource):
    assert True


def test_two(resource):
    assert True

if __name__ == '__main__':
    import subprocess
    # Run pytest with 2 parallel workers
    result = subprocess.run(['pytest', '-n', '2', '--capture=no'], capture_output=True, text=True)
    print(result.stdout)
    # Check output for setup/teardown counts
    setup_runs = result.stdout.count('Setup called')
    teardown_runs = result.stdout.count('Teardown called')
    assert setup_runs == 2, f'Expected 2 setup calls, got {setup_runs}'
    assert teardown_runs == 2, f'Expected 2 teardown calls, got {teardown_runs}'
    assert 'failed' not in result.stdout.lower(), 'Some tests failed'

This code defines a pytest fixture resource with module scope. It increments counters and prints messages when setup and teardown run.

Two test functions use this fixture. When running with pytest-xdist using 2 workers (-n 2), the fixture setup and teardown run once per worker, so twice total.

The __main__ block runs pytest programmatically with parallel workers and captures output. It counts how many times the setup and teardown messages appear to verify the fixture scope behavior.

Assertions check that both tests pass and the fixture setup/teardown run exactly twice, matching the expected behavior for module scope with parallel workers.

This approach helps beginners see how fixture scope affects parallel test runs and how to verify it.

Common Mistakes - 4 Pitfalls
{'mistake': 'Using function scope fixture expecting it to run once per module', 'why_bad': 'Function scope fixtures run before each test function, so setup runs multiple times, not once per module', 'correct_approach': "Set fixture scope to 'module' to run setup once per module per worker"}
{'mistake': 'Not using pytest-xdist and expecting parallel execution', 'why_bad': 'Without pytest-xdist, tests run sequentially, so parallel fixture behavior cannot be observed', 'correct_approach': "Install and use pytest-xdist with '-n' option to run tests in parallel"}
Sharing mutable global state between workers
{'mistake': "Using print statements without '--capture=no' option", 'why_bad': 'Pytest captures output by default, so print statements may not appear in console, confusing beginners', 'correct_approach': "Run pytest with '--capture=no' to see print output during test runs"}
Bonus Challenge

Now add data-driven testing with 3 different inputs using the same fixture and verify fixture setup runs only twice total

Show Hint

Practice

(1/5)
1. What does the scope='session' parameter in a pytest fixture control?
easy
A. The fixture runs once per entire test session.
B. The fixture runs once per test function.
C. The fixture runs once per test class.
D. The fixture runs once per test module.

Solution

  1. Step 1: Understand fixture scopes in pytest

    Pytest fixtures can have different scopes like function, class, module, and session, which control how often the fixture setup runs.
  2. Step 2: Identify what session scope means

    Session scope means the fixture runs only once for the entire test session, regardless of how many tests use it.
  3. Final Answer:

    The fixture runs once per entire test session. -> Option A
  4. Quick Check:

    scope='session' = runs once per session [OK]
Hint: Session scope means one setup for all tests in session [OK]
Common Mistakes:
  • Confusing session scope with function scope
  • Thinking session scope runs per test module
  • Assuming session scope runs per test class
2. Which of the following is the correct syntax to define a pytest fixture with session scope?
easy
A. @pytest.fixture(scope='function')
B. @pytest.fixture(scope='session')
C. @pytest.fixture(session=True)
D. @pytest.fixture(scope=session)

Solution

  1. Step 1: Recall pytest fixture syntax

    Pytest fixtures use the decorator @pytest.fixture() with optional parameters like scope as a string.
  2. Step 2: Identify correct scope parameter usage

    The scope parameter must be a string, so scope='session' is correct. Options C and D are invalid syntax.
  3. Final Answer:

    @pytest.fixture(scope='session') -> Option B
  4. Quick Check:

    Correct syntax uses scope='session' string [OK]
Hint: Use quotes around scope value: scope='session' [OK]
Common Mistakes:
  • Omitting quotes around 'session'
  • Using invalid keyword arguments
  • Confusing scope with boolean flags
3. Consider this pytest fixture and test code run with 2 parallel workers:
@pytest.fixture(scope='session')
def resource():
    print('Setup resource')
    yield
    print('Teardown resource')

def test_a(resource):
    pass

def test_b(resource):
    pass

How many times will 'Setup resource' be printed during the entire test run?
medium
A. Once
B. Zero times
C. Twice
D. Four times

Solution

  1. Step 1: Understand session scope with parallel workers

    When running tests in parallel with pytest-xdist, each worker runs its own session, so session-scoped fixtures run once per worker.
  2. Step 2: Calculate total setup calls

    With 2 workers, the fixture setup runs once per worker, so 'Setup resource' prints twice.
  3. Final Answer:

    Twice -> Option C
  4. Quick Check:

    Session scope runs once per worker = 2 times [OK]
Hint: Session scope runs once per worker in parallel tests [OK]
Common Mistakes:
  • Assuming session scope runs only once globally
  • Ignoring parallel worker count
  • Confusing function scope with session scope
4. You have a session-scoped fixture used in parallel tests with 3 workers. You notice the fixture setup runs 3 times, but you want it to run only once globally. What is the likely cause and fix?
medium
A. Cause: fixture is not used; Fix: add fixture to tests.
B. Cause: fixture scope is function; Fix: change to session scope.
C. Cause: parallel tests disabled; Fix: enable parallel execution.
D. Cause: session scope runs per worker; Fix: use a database or external service to share state.

Solution

  1. Step 1: Identify why session scope runs multiple times

    In parallel testing, session scope runs once per worker, so with 3 workers, setup runs 3 times.
  2. Step 2: Understand how to share fixture state globally

    To run setup only once globally, you must share state outside pytest workers, e.g., via a database or external service.
  3. Final Answer:

    Cause: session scope runs per worker; Fix: use a database or external service to share state. -> Option D
  4. Quick Check:

    Session scope per worker needs external sharing [OK]
Hint: Session scope runs per worker; share state externally to fix [OK]
Common Mistakes:
  • Thinking session scope runs once globally in parallel
  • Changing scope to function instead of sharing state
  • Ignoring parallel execution effects
5. You want to run expensive setup code only once for all tests across 4 parallel pytest workers. Which approach correctly ensures this behavior?
hard
A. Use scope='session' fixture and implement external resource locking (e.g., file lock or database).
B. Use scope='function' fixture and cache results in a global variable.
C. Use scope='session' fixture and rely on pytest-xdist to share it automatically.
D. Use scope='module' fixture and run tests sequentially.

Solution

  1. Step 1: Understand session scope behavior with parallel workers

    Session scope runs once per worker, so with 4 workers, setup runs 4 times unless shared externally.
  2. Step 2: Identify how to run setup only once globally

    Implementing external resource locking (like a file lock or database flag) ensures only one worker runs the expensive setup.
  3. Final Answer:

    Use scope='session' fixture and implement external resource locking (e.g., file lock or database). -> Option A
  4. Quick Check:

    External locking + session scope = single global setup [OK]
Hint: Combine session scope with external locking for global setup [OK]
Common Mistakes:
  • Assuming pytest-xdist shares session fixtures automatically
  • Using function scope and expecting single setup
  • Running tests sequentially defeats parallel purpose