0
# Fixtures and Markers
1
2
pytest-cov provides built-in pytest fixtures and markers that allow fine-grained control over coverage measurement at the test level. These tools enable developers to exclude specific tests from coverage or access the underlying coverage object for advanced scenarios.
3
4
## Capabilities
5
6
### Coverage Control Fixtures
7
8
Fixtures that control coverage behavior during test execution.
9
10
```python { .api }
11
@pytest.fixture
12
def no_cover():
13
"""
14
A pytest fixture to disable coverage for specific tests.
15
16
When used as a fixture parameter, disables coverage measurement
17
for the duration of the test function. The fixture itself does
18
nothing - its presence signals the coverage system to pause
19
measurement.
20
21
Usage:
22
def test_excluded_function(no_cover):
23
# This test will not be included in coverage reports
24
pass
25
"""
26
27
@pytest.fixture
28
def cov(request):
29
"""
30
A pytest fixture to provide access to the underlying coverage object.
31
32
Returns the active coverage.Coverage instance if coverage is enabled,
33
allowing tests to inspect coverage state, access configuration, or
34
perform advanced coverage operations.
35
36
Args:
37
request: pytest request object
38
39
Returns:
40
coverage.Coverage: Active coverage instance, or None if disabled
41
42
Usage:
43
def test_coverage_info(cov):
44
if cov:
45
print(f"Data file: {cov.config.data_file}")
46
print(f"Source: {cov.config.source}")
47
"""
48
```
49
50
**Usage Examples:**
51
52
```python
53
import pytest
54
55
def test_normal_coverage():
56
"""This test will be included in coverage measurement."""
57
import mymodule
58
assert mymodule.function() == "expected"
59
60
def test_excluded_with_fixture(no_cover):
61
"""This test will be excluded from coverage."""
62
import mymodule
63
# This code execution won't count toward coverage
64
mymodule.debug_function()
65
66
def test_coverage_access(cov):
67
"""Test that can access coverage configuration."""
68
if cov:
69
# Can inspect coverage settings
70
assert cov.config.data_file
71
assert hasattr(cov.config, 'source')
72
73
# Test code still gets measured for coverage
74
import mymodule
75
mymodule.function()
76
77
def test_both_fixtures(cov, no_cover):
78
"""Test using both fixtures - coverage access but no measurement."""
79
if cov:
80
print(f"Coverage enabled but test excluded")
81
# This test code won't be measured for coverage
82
```
83
84
### Coverage Control Markers
85
86
pytest markers that provide declarative coverage control.
87
88
```python { .api }
89
# Marker registration (done automatically by plugin)
90
config.addinivalue_line('markers', 'no_cover: disable coverage for this test.')
91
```
92
93
The `no_cover` marker provides an alternative to the fixture for excluding tests from coverage measurement.
94
95
**Usage Examples:**
96
97
```python
98
import pytest
99
100
@pytest.mark.no_cover
101
def test_excluded_with_marker():
102
"""This test will be excluded from coverage measurement."""
103
import mymodule
104
# Code execution here won't count toward coverage
105
mymodule.debug_function()
106
107
@pytest.mark.no_cover
108
def test_debugging_code():
109
"""Useful for tests that exercise debugging or development-only code."""
110
import mymodule
111
mymodule.internal_debug_function()
112
113
class TestDevelopmentFeatures:
114
"""Test class for development features."""
115
116
@pytest.mark.no_cover
117
def test_dev_feature_a(self):
118
"""Development feature test excluded from coverage."""
119
pass
120
121
def test_production_feature(self):
122
"""Production feature test included in coverage."""
123
pass
124
```
125
126
### Fixture Implementation Details
127
128
Internal implementation of the fixture system and coverage control.
129
130
```python { .api }
131
def cov(request):
132
"""
133
Implementation of the cov fixture.
134
135
Checks if the '_cov' plugin is registered and active, then
136
returns the coverage controller's coverage instance if available.
137
138
Returns None if:
139
- Coverage plugin is not registered
140
- Coverage plugin has no active controller
141
- Coverage controller has no coverage instance
142
"""
143
```
144
145
The fixture implementation:
146
147
1. **Plugin Detection**: Uses `pluginmanager.hasplugin('_cov')` to check if coverage is active
148
2. **Controller Access**: Gets the `CovPlugin` instance via `pluginmanager.getplugin('_cov')`
149
3. **Coverage Instance**: Returns `plugin.cov_controller.cov` if available
150
4. **Graceful Fallback**: Returns `None` if any step fails
151
152
### Marker Processing
153
154
How the coverage system processes markers and fixtures during test execution.
155
156
```python { .api }
157
def pytest_runtest_call(self, item):
158
"""
159
Process coverage control markers and fixtures during test execution.
160
161
Checks for:
162
- @pytest.mark.no_cover marker on test function
163
- 'no_cover' in test's fixture names
164
165
If either is found, pauses coverage before test execution
166
and resumes coverage after test completion.
167
"""
168
```
169
170
The marker/fixture processing logic:
171
172
```python
173
# Check for marker or fixture
174
if item.get_closest_marker('no_cover') or 'no_cover' in getattr(item, 'fixturenames', ()):
175
self.cov_controller.pause()
176
yield # Execute test
177
self.cov_controller.resume()
178
else:
179
yield # Execute test normally with coverage
180
```
181
182
## Integration Patterns
183
184
### Combining Fixtures and Markers
185
186
Different ways to control coverage in test scenarios:
187
188
```python
189
# Using marker (preferred for permanent exclusions)
190
@pytest.mark.no_cover
191
def test_debug_helper():
192
pass
193
194
# Using fixture (useful for conditional logic)
195
def test_conditional_coverage(no_cover, some_condition):
196
if some_condition:
197
# Test logic that should be excluded
198
pass
199
200
# Accessing coverage while excluding test
201
@pytest.mark.no_cover
202
def test_coverage_inspection(cov):
203
if cov:
204
print(f"Coverage active but test excluded")
205
```
206
207
### Conditional Coverage Control
208
209
Using fixtures for dynamic coverage control:
210
211
```python
212
@pytest.fixture
213
def maybe_no_cover(request):
214
"""Conditionally disable coverage based on test conditions."""
215
if request.config.getoption("--debug-mode"):
216
request.getfixturevalue("no_cover")
217
218
def test_with_conditional_coverage(maybe_no_cover):
219
"""Coverage depends on command-line flag."""
220
# Test code here
221
pass
222
```
223
224
### Coverage Inspection Patterns
225
226
Common patterns for using the `cov` fixture:
227
228
```python
229
def test_coverage_configuration(cov):
230
"""Inspect coverage configuration."""
231
if cov:
232
assert cov.config.branch is True
233
assert cov.config.source == ['mypackage']
234
235
def test_coverage_data_access(cov):
236
"""Access coverage measurement data."""
237
if cov:
238
# Get current coverage data
239
data = cov.get_data()
240
measured_files = data.measured_files()
241
assert len(measured_files) > 0
242
243
def test_coverage_reporting(cov, tmp_path):
244
"""Generate custom coverage reports."""
245
if cov:
246
# Generate custom report
247
report_file = tmp_path / "custom_report.txt"
248
with open(report_file, 'w') as f:
249
cov.report(file=f)
250
assert report_file.exists()
251
```
252
253
### Test Organization
254
255
Organizing tests with coverage control:
256
257
```python
258
class TestProductionCode:
259
"""Tests for production functionality - all measured."""
260
261
def test_feature_a(self):
262
import mymodule
263
assert mymodule.feature_a()
264
265
def test_feature_b(self):
266
import mymodule
267
assert mymodule.feature_b()
268
269
class TestDevelopmentCode:
270
"""Tests for development/debug code - excluded from coverage."""
271
272
@pytest.mark.no_cover
273
def test_debug_mode(self):
274
import mymodule
275
mymodule.enable_debug_mode()
276
277
@pytest.mark.no_cover
278
def test_development_feature(self):
279
import mymodule
280
mymodule.experimental_feature()
281
282
class TestCoverageAware:
283
"""Tests that need coverage introspection."""
284
285
def test_with_coverage_check(self, cov):
286
"""Test that verifies coverage is working."""
287
if cov:
288
# Verify coverage is measuring our module
289
import mymodule
290
mymodule.function()
291
292
data = cov.get_data()
293
assert any('mymodule' in f for f in data.measured_files())
294
```