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
sessionscope for fixtures that return mutable objects, causing shared state bugs. - Expecting
functionscope fixtures to persist data across tests. - Not using
yieldfor 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:
| Scope | Description | When to Use |
|---|---|---|
| function | Runs once per test function | Default; isolate tests |
| class | Runs once per test class | Setup shared state for class tests |
| module | Runs once per module (file) | Setup expensive resources for many tests |
| session | Runs once per test session | Setup 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.