0
# Pytest Integration
1
2
Deep integration with pytest providing custom hooks, CLI options, automatic test file discovery, and seamless integration with pytest plugins and reporting systems.
3
4
## Capabilities
5
6
### Pytest Plugin Hooks
7
8
Core pytest plugin hooks that integrate Tavern into the pytest framework, enabling automatic test discovery and execution.
9
10
```python { .api }
11
def pytest_addhooks(pluginmanager):
12
"""
13
Register custom Tavern hooks with pytest.
14
15
Parameters:
16
- pluginmanager: Pytest plugin manager instance
17
"""
18
19
def pytest_addoption(parser):
20
"""
21
Add Tavern-specific command line options to pytest.
22
23
Parameters:
24
- parser: Pytest argument parser
25
"""
26
27
def pytest_collect_file(parent, path):
28
"""
29
Collect Tavern YAML test files during pytest discovery.
30
31
Parameters:
32
- parent: Parent pytest node
33
- path: File path being considered for collection
34
35
Returns:
36
TavernFile instance if file matches Tavern pattern, None otherwise
37
"""
38
```
39
40
### Parser Option Management
41
42
Programmatic interface for adding Tavern CLI options to pytest parsers.
43
44
```python { .api }
45
def add_parser_options(parser_addoption, with_defaults=True):
46
"""
47
Add Tavern CLI options to a parser programmatically.
48
49
Parameters:
50
- parser_addoption: Parser add_option function
51
- with_defaults: Whether to include default values
52
"""
53
```
54
55
### Custom Hook Execution
56
57
Interface for calling custom Tavern hooks during test execution.
58
59
```python { .api }
60
def call_hook(test_block_config, hookname, **kwargs):
61
"""
62
Call a custom Tavern hook during test execution.
63
64
Parameters:
65
- test_block_config: Test configuration object
66
- hookname: Name of hook to call
67
- **kwargs: Arguments to pass to hook
68
"""
69
```
70
71
## Custom Hooks
72
73
### Beta Hook Specifications
74
75
Custom hooks for extending Tavern test execution with user-defined functionality.
76
77
```python { .api }
78
def pytest_tavern_beta_before_every_test_run(
79
test_dict: dict,
80
variables: dict
81
) -> None:
82
"""
83
Hook called before each test execution.
84
85
Parameters:
86
- test_dict: Test definition dictionary
87
- variables: Current test variables
88
"""
89
90
def pytest_tavern_beta_after_every_test_run(
91
test_dict: dict,
92
variables: dict
93
) -> None:
94
"""
95
Hook called after each test execution.
96
97
Parameters:
98
- test_dict: Test definition dictionary
99
- variables: Updated test variables
100
"""
101
102
def pytest_tavern_beta_after_every_response(
103
expected: Any,
104
response: Any
105
) -> None:
106
"""
107
Hook called after each response is received.
108
109
Parameters:
110
- expected: Expected response specification
111
- response: Actual response object
112
"""
113
114
def pytest_tavern_beta_before_every_request(
115
request_args: MutableMapping
116
) -> None:
117
"""
118
Hook called before each request is sent.
119
120
Parameters:
121
- request_args: Mutable request arguments dictionary
122
"""
123
```
124
125
## CLI Options
126
127
### Tavern-Specific Options
128
129
Command line options added to pytest for controlling Tavern behavior.
130
131
**Core Configuration:**
132
- `--tavern-global-cfg`: Path to global configuration file
133
- `--tavern-strict`: Response matching strictness level
134
- `--tavern-file-path-regex`: Regex pattern for test files (default: `r".+\.tavern\.ya?ml$"`)
135
136
**Backend Selection:**
137
- `--tavern-http-backend`: HTTP backend plugin name (default: "requests")
138
- `--tavern-mqtt-backend`: MQTT backend plugin name (default: "paho-mqtt")
139
- `--tavern-grpc-backend`: gRPC backend plugin name (default: "grpc")
140
141
**Debugging Options:**
142
- `--tavern-use-default-traceback`: Use Python-style tracebacks
143
- `--tavern-setup-init-logging`: Setup simple logger for initialization
144
145
**HTTP-Specific:**
146
- `--tavern-always-follow-redirects`: Always follow HTTP redirects
147
148
## Usage Examples
149
150
### Basic Pytest Integration
151
152
```bash
153
# Run Tavern tests with pytest
154
pytest tests/ -v
155
156
# Run specific Tavern test file
157
pytest test_api.tavern.yaml -v
158
159
# Run with Tavern-specific options
160
pytest tests/ --tavern-global-cfg config.yaml --tavern-strict
161
```
162
163
### Custom Hook Implementation
164
165
```python
166
# conftest.py
167
def pytest_tavern_beta_before_every_test_run(test_dict, variables):
168
"""Add custom setup before each test."""
169
print(f"Running test: {test_dict.get('test_name', 'Unknown')}")
170
171
# Add dynamic variables
172
variables['timestamp'] = str(int(time.time()))
173
variables['test_id'] = str(uuid.uuid4())
174
175
def pytest_tavern_beta_after_every_response(expected, response):
176
"""Log response details."""
177
if hasattr(response, 'status_code'):
178
print(f"Response status: {response.status_code}")
179
180
def pytest_tavern_beta_before_every_request(request_args):
181
"""Modify requests before sending."""
182
# Add common headers
183
if 'headers' not in request_args:
184
request_args['headers'] = {}
185
request_args['headers']['X-Test-Run'] = 'true'
186
```
187
188
### Programmatic Parser Configuration
189
190
```python
191
import argparse
192
from tavern._core.pytest import add_parser_options
193
194
# Create custom parser with Tavern options
195
parser = argparse.ArgumentParser()
196
add_parser_options(parser.add_argument, with_defaults=True)
197
198
# Parse arguments
199
args = parser.parse_args([
200
'--tavern-global-cfg', 'config.yaml',
201
'--tavern-strict',
202
'--tavern-http-backend', 'custom_requests'
203
])
204
```
205
206
### File Discovery and Collection
207
208
```python
209
# Custom pytest plugin using Tavern collection
210
class CustomTavernPlugin:
211
def pytest_collect_file(self, parent, path):
212
"""Collect custom Tavern files."""
213
if path.ext == ".yaml" and "api_test" in path.basename:
214
# Use Tavern's collection logic
215
from tavern._core.pytest import pytest_collect_file
216
return pytest_collect_file(parent, path)
217
```
218
219
### Configuration Integration
220
221
```yaml
222
# pytest.ini
223
[tool:pytest]
224
addopts =
225
--tavern-global-cfg=tests/global_config.yaml
226
--tavern-strict
227
--tavern-http-backend=requests
228
-v
229
230
testpaths = tests/
231
python_files = *.tavern.yaml
232
```
233
234
### Advanced Hook Usage
235
236
```python
237
# Plugin with comprehensive hook usage
238
class TavernTestPlugin:
239
def __init__(self):
240
self.test_results = []
241
self.start_time = None
242
243
def pytest_tavern_beta_before_every_test_run(self, test_dict, variables):
244
self.start_time = time.time()
245
246
# Set up test-specific configuration
247
test_name = test_dict.get('test_name', 'unknown')
248
variables['test_start_time'] = self.start_time
249
variables['test_environment'] = os.getenv('TEST_ENV', 'local')
250
251
print(f"Starting test: {test_name}")
252
253
def pytest_tavern_beta_after_every_test_run(self, test_dict, variables):
254
duration = time.time() - self.start_time
255
test_name = test_dict.get('test_name', 'unknown')
256
257
self.test_results.append({
258
'name': test_name,
259
'duration': duration,
260
'variables_used': list(variables.keys())
261
})
262
263
print(f"Completed test: {test_name} in {duration:.2f}s")
264
265
def pytest_tavern_beta_before_every_request(self, request_args):
266
# Add request tracing
267
if 'headers' not in request_args:
268
request_args['headers'] = {}
269
request_args['headers']['X-Trace-ID'] = str(uuid.uuid4())
270
271
# Log outgoing requests
272
method = request_args.get('method', 'GET')
273
url = request_args.get('url', 'unknown')
274
print(f"Sending {method} request to {url}")
275
276
def pytest_tavern_beta_after_every_response(self, expected, response):
277
# Validate response timing
278
if hasattr(response, 'elapsed'):
279
if response.elapsed.total_seconds() > 5.0:
280
print(f"WARNING: Slow response ({response.elapsed.total_seconds():.2f}s)")
281
282
# Log response status
283
if hasattr(response, 'status_code'):
284
print(f"Received response: {response.status_code}")
285
```
286
287
## Integration with Pytest Ecosystem
288
289
### Pytest Plugin Compatibility
290
291
```python
292
# Works with pytest-xdist for parallel execution
293
pytest tests/ -n auto --tavern-global-cfg config.yaml
294
295
# Works with pytest-cov for coverage
296
pytest tests/ --cov=myapp --tavern-strict
297
298
# Works with pytest-html for HTML reports
299
pytest tests/ --html=report.html --self-contained-html
300
```
301
302
### Custom Test Item Classes
303
304
```python { .api }
305
# Internal classes used by pytest integration
306
class TavernFile:
307
"""Represents a Tavern YAML test file in pytest collection."""
308
309
class TavernItem:
310
"""Represents an individual Tavern test case in pytest."""
311
```
312
313
## Types
314
315
```python { .api }
316
from typing import Any, MutableMapping
317
from _pytest.config import Config
318
from _pytest.nodes import File, Item
319
320
TestConfig = "tavern._core.pytest.config.TestConfig"
321
```