0
# Fixtures and Dependency Injection
1
2
Comprehensive fixture system for managing test dependencies, setup, and teardown with support for multiple scopes, parametrization, and automatic resolution. The fixture system provides a powerful dependency injection framework that eliminates the need for traditional setUp/tearDown methods.
3
4
## Capabilities
5
6
### Fixture Declaration
7
8
Decorator for marking functions as fixture factories that provide reusable test components.
9
10
```python { .api }
11
def fixture(
12
fixture_function=None,
13
*,
14
scope: str = "function",
15
params=None,
16
autouse: bool = False,
17
ids=None,
18
name: str | None = None
19
):
20
"""
21
Mark function as fixture factory.
22
23
Parameters:
24
- fixture_function: Function to mark as fixture (when used as decorator)
25
- scope: Fixture scope ("function", "class", "module", "package", "session")
26
- params: List of parameters for parametrized fixtures
27
- autouse: Whether fixture runs automatically for all tests
28
- ids: List of test IDs for parametrized fixtures
29
- name: Alternative name for the fixture
30
31
Returns:
32
FixtureFunctionMarker or FixtureFunctionDefinition
33
"""
34
```
35
36
**Usage Example:**
37
38
```python
39
import pytest
40
import tempfile
41
import os
42
43
# Basic fixture
44
@pytest.fixture
45
def sample_data():
46
return [1, 2, 3, 4, 5]
47
48
# Fixture with teardown
49
@pytest.fixture
50
def temp_file():
51
fd, path = tempfile.mkstemp()
52
yield path # This is where the test runs
53
os.close(fd)
54
os.unlink(path)
55
56
# Scoped fixture
57
@pytest.fixture(scope="module")
58
def database_connection():
59
connection = create_db_connection()
60
yield connection
61
connection.close()
62
63
# Parametrized fixture
64
@pytest.fixture(params=[1, 2, 3])
65
def number(request):
66
return request.param
67
68
# Autouse fixture
69
@pytest.fixture(autouse=True)
70
def setup_test_environment():
71
setup_environment()
72
yield
73
cleanup_environment()
74
75
# Named fixture
76
@pytest.fixture(name="data")
77
def sample_data_fixture():
78
return {"key": "value"}
79
80
def test_with_fixtures(sample_data, temp_file, number, data):
81
assert len(sample_data) == 5
82
assert os.path.exists(temp_file)
83
assert number in [1, 2, 3]
84
assert data["key"] == "value"
85
```
86
87
### Legacy Fixture Support
88
89
```python { .api }
90
def yield_fixture(*args, **kwargs):
91
"""
92
Legacy alias for fixture decorator (deprecated).
93
Use pytest.fixture instead.
94
"""
95
```
96
97
### Fixture Request
98
99
Object passed to fixture functions providing access to the requesting test context and fixture management capabilities.
100
101
```python { .api }
102
class FixtureRequest:
103
"""Request object passed to fixture functions."""
104
105
# Core attributes
106
node: Node # Test node that requested the fixture
107
scope: str # Fixture scope
108
fixturename: str # Name of the fixture
109
config: Config # pytest configuration object
110
function: Callable | None # Test function (if applicable)
111
cls: type | None # Test class (if applicable)
112
instance: Any | None # Test class instance (if applicable)
113
module: Any | None # Test module
114
param: Any # Current parameter (for parametrized fixtures)
115
keywords: dict # Test keywords/markers
116
117
def getfixturevalue(self, argname: str) -> Any:
118
"""
119
Get value of another fixture by name.
120
121
Parameters:
122
- argname: Name of fixture to retrieve
123
124
Returns:
125
Fixture value
126
"""
127
128
def applymarker(self, marker) -> None:
129
"""
130
Apply marker to the test node.
131
132
Parameters:
133
- marker: Marker to apply
134
"""
135
136
def raiseerror(self, msg: str | None) -> None:
137
"""
138
Raise FixtureLookupError with given message.
139
140
Parameters:
141
- msg: Error message
142
"""
143
144
@property
145
def fspath(self):
146
"""Legacy property for file path (use node.path instead)."""
147
```
148
149
**Usage Example:**
150
151
```python
152
import pytest
153
154
@pytest.fixture
155
def user_data(request):
156
# Access test function name
157
test_name = request.node.name
158
159
# Get configuration
160
config_value = request.config.getini("test_setting")
161
162
# Access other fixtures
163
database = request.getfixturevalue("database_connection")
164
165
# Create user based on test context
166
if "admin" in test_name:
167
return create_admin_user(database)
168
else:
169
return create_regular_user(database)
170
171
@pytest.fixture(params=["sqlite", "postgresql"])
172
def database_type(request):
173
return request.param
174
175
@pytest.fixture
176
def configured_database(request, database_type):
177
# Access parameter from parametrized dependency
178
db_type = database_type
179
config = request.config
180
181
return setup_database(db_type, config)
182
```
183
184
### Fixture Definition
185
186
Container for fixture definitions with metadata and execution logic.
187
188
```python { .api }
189
class FixtureDef:
190
"""Container for fixture definitions."""
191
192
# Core attributes
193
argname: str # Fixture argument name
194
func: Callable # Fixture function
195
scope: str # Fixture scope
196
params: list | None # Parameters for parametrized fixtures
197
autouse: bool # Whether fixture is automatically used
198
ids: list | None # Parameter IDs
199
200
# Execution methods (internal use)
201
def execute(self, request: FixtureRequest): ...
202
def finish(self, request: FixtureRequest): ...
203
```
204
205
### Fixture Exceptions
206
207
Exception raised when fixture cannot be found or resolved.
208
209
```python { .api }
210
class FixtureLookupError(Exception):
211
"""
212
Raised when fixture cannot be found or resolved.
213
214
This exception is raised when:
215
- A fixture name is not found
216
- Circular fixture dependencies are detected
217
- Fixture scope conflicts occur
218
"""
219
```
220
221
## Fixture Scopes
222
223
```python { .api }
224
# Fixture scope hierarchy (from narrowest to broadest)
225
FIXTURE_SCOPES = [
226
"function", # Default: new instance per test function
227
"class", # One instance per test class
228
"module", # One instance per test module
229
"package", # One instance per test package
230
"session" # One instance per test session
231
]
232
```
233
234
## Built-in Fixtures
235
236
pytest provides many built-in fixtures automatically available in all tests:
237
238
```python { .api }
239
# Core built-in fixtures (examples)
240
def test_with_builtins(
241
request, # FixtureRequest object
242
config, # Config object
243
monkeypatch, # MonkeyPatch object
244
capfd, # CaptureFixture for file descriptors
245
capsys, # CaptureFixture for sys.stdout/stderr
246
caplog, # LogCaptureFixture
247
tmp_path, # pathlib.Path to temporary directory
248
tmp_path_factory, # TempPathFactory
249
pytester, # Pytester for testing pytest plugins
250
recwarn # WarningsRecorder
251
):
252
pass
253
```
254
255
## Advanced Fixture Patterns
256
257
### Fixture Dependencies
258
259
```python
260
@pytest.fixture
261
def database():
262
return setup_database()
263
264
@pytest.fixture
265
def user(database):
266
return create_user(database)
267
268
@pytest.fixture
269
def admin_user(database):
270
return create_admin_user(database)
271
272
def test_user_permissions(user, admin_user):
273
assert not user.is_admin
274
assert admin_user.is_admin
275
```
276
277
### Conditional Fixtures
278
279
```python
280
@pytest.fixture
281
def storage_backend(request):
282
if request.config.getoption("--use-redis"):
283
return RedisStorage()
284
else:
285
return MemoryStorage()
286
```
287
288
### Factory Fixtures
289
290
```python
291
@pytest.fixture
292
def user_factory():
293
created_users = []
294
295
def create_user(**kwargs):
296
user = User(**kwargs)
297
created_users.append(user)
298
return user
299
300
yield create_user
301
302
# Cleanup
303
for user in created_users:
304
user.delete()
305
306
def test_multiple_users(user_factory):
307
user1 = user_factory(name="Alice")
308
user2 = user_factory(name="Bob")
309
assert user1.name != user2.name
310
```