0
0
PytestHow-ToBeginner ยท 3 min read

How to Use Fixture with Scope in pytest for Efficient Testing

In pytest, you use the @pytest.fixture(scope='scope_name') decorator to define a fixture with a specific scope like function, class, module, or session. This controls how often the fixture setup runs, helping you optimize test performance and resource usage.
๐Ÿ“

Syntax

Use the @pytest.fixture decorator with the scope parameter to set the fixture's lifetime. Common scopes are:

  • function: runs once per test function (default)
  • class: runs once per test class
  • module: runs once per module (file)
  • session: runs once per entire test session

The fixture function contains setup code and optionally returns data for tests.

python
@pytest.fixture(scope='scope_name')
def fixture_name():
    # setup code
    yield resource
    # teardown code (after yield)
๐Ÿ’ป

Example

This example shows a fixture with module scope that runs once for all tests in the module. It sets up a resource and cleans it after all tests finish.

python
import pytest

@pytest.fixture(scope='module')
def resource():
    print('\nSetup resource')
    yield {'data': 123}
    print('\nTeardown resource')

def test_one(resource):
    assert resource['data'] == 123

def test_two(resource):
    assert resource['data'] > 100
Output
Setup resource . . Teardown resource
โš ๏ธ

Common Pitfalls

Common mistakes when using fixture scopes include:

  • Using session scope for fixtures that return mutable objects, causing shared state bugs.
  • Expecting function scope fixtures to persist data across tests.
  • Not using yield for teardown, leading to resource leaks.

Always choose the narrowest scope needed and avoid side effects between tests.

python
import pytest

# Wrong: mutable shared state with session scope
@pytest.fixture(scope='session')
def shared_list():
    return []  # mutable shared object

def test_append(shared_list):
    shared_list.append(1)
    assert shared_list == [1]

def test_clear(shared_list):
    shared_list.clear()
    assert shared_list == []

# Right: use function scope to isolate
@pytest.fixture(scope='function')
def isolated_list():
    return []

def test_append_isolated(isolated_list):
    isolated_list.append(1)
    assert isolated_list == [1]

def test_clear_isolated(isolated_list):
    assert isolated_list == []
๐Ÿ“Š

Quick Reference

Fixture scopes control how often setup/teardown runs:

ScopeDescriptionWhen to Use
functionRuns once per test functionDefault; isolate tests
classRuns once per test classSetup shared state for class tests
moduleRuns once per module (file)Setup expensive resources for many tests
sessionRuns once per test sessionSetup global resources, e.g., DB connections
โœ…

Key Takeaways

Use @pytest.fixture(scope='scope_name') to control fixture lifetime.
Choose the narrowest scope needed to avoid shared state bugs.
Use yield in fixtures to handle setup and teardown cleanly.
Avoid mutable shared objects in session-scoped fixtures.
Module and session scopes improve performance by reducing setup calls.