0
# Test Parameterization
1
2
Powerful parameterization system supporting multiple parameter sets with optional decorators for enhanced functionality.
3
4
## Capabilities
5
6
### Basic Parameterization
7
8
The core `params` decorator for creating multiple test instances with different input values.
9
10
```python { .api }
11
class params:
12
"""
13
Parameterization decorator for creating multiple test instances.
14
15
Can be used as a decorator directly or with additional decorators
16
via class item access.
17
"""
18
19
def __init__(self, *args, **kwargs):
20
"""
21
Initialize parameterization with positional and keyword arguments.
22
23
Args:
24
*args: Positional arguments to pass to the test
25
**kwargs: Keyword arguments to pass to the test
26
"""
27
28
def __call__(self, fn: F) -> F:
29
"""
30
Apply parameters to the test function or class constructor.
31
32
Args:
33
fn: Function or class to parameterize
34
35
Returns:
36
The parameterized function/class
37
"""
38
39
def __class_getitem__(cls, item) -> Callable[..., Parameterized]:
40
"""
41
Create parameterization with additional decorators.
42
43
Args:
44
item: Single decorator or tuple of decorators
45
46
Returns:
47
Callable that creates Parameterized instance with decorators
48
"""
49
```
50
51
#### Usage Example - Class-based
52
53
```python
54
from vedro import Scenario, params
55
56
class Scenario(vedro.Scenario):
57
subject = "mathematical operations"
58
59
@params(2, 3, 5) # a=2, b=3, expected=5
60
@params(10, 15, 25) # a=10, b=15, expected=25
61
@params(-5, 8, 3) # a=-5, b=8, expected=3
62
def __init__(self, a, b, expected):
63
self.a = a
64
self.b = b
65
self.expected = expected
66
67
def when_numbers_are_added(self):
68
self.result = self.a + self.b
69
70
def then_result_matches_expected(self):
71
assert self.result == self.expected
72
```
73
74
#### Usage Example - Function-based
75
76
```python
77
from vedro import scenario, params, given, when, then, ensure
78
79
@params("admin", 200)
80
@params("user", 200)
81
@params("guest", 403)
82
@scenario("API access with different user roles")
83
def test_api_access(role, expected_status):
84
85
@given(f"user with {role} role")
86
def setup():
87
return authenticate_user_with_role(role)
88
89
@when("user accesses protected resource")
90
def action(user):
91
return api_request("/protected-resource", auth=user.token)
92
93
@then(f"response has status {expected_status}")
94
def verification(response):
95
ensure(response.status_code).equals(expected_status)
96
```
97
98
### Parameterization with Keywords
99
100
Support for keyword arguments in parameterization for more readable tests.
101
102
```python
103
@params(username="admin", password="admin123", should_succeed=True)
104
@params(username="user", password="wrongpass", should_succeed=False)
105
@params(username="", password="", should_succeed=False)
106
@scenario("Login with various credentials")
107
def test_login(username, password, should_succeed):
108
109
@given("login credentials")
110
def setup():
111
return {"username": username, "password": password}
112
113
@when("user attempts login")
114
def action(credentials):
115
try:
116
result = login(credentials["username"], credentials["password"])
117
return {"success": True, "result": result}
118
except AuthenticationError as e:
119
return {"success": False, "error": str(e)}
120
121
@then("login outcome matches expectation")
122
def verification(outcome):
123
ensure(outcome["success"]).equals(should_succeed)
124
```
125
126
### Parameterization with Decorators
127
128
Advanced parameterization that applies additional decorators to specific parameter sets.
129
130
```python
131
from vedro import skip
132
133
# Apply skip decorator to specific parameter sets
134
@params[skip("Flaky test")]("slow_endpoint", 30)
135
@params("fast_endpoint", 5)
136
@params("medium_endpoint", 15)
137
@scenario("API response times")
138
def test_response_times(endpoint, max_time):
139
140
@when(f"requesting {endpoint}")
141
def action():
142
start_time = time.time()
143
response = api_request(f"/api/{endpoint}")
144
duration = time.time() - start_time
145
return {"response": response, "duration": duration}
146
147
@then(f"response time is under {max_time} seconds")
148
def verification(result):
149
ensure(result["response"].status_code).equals(200)
150
ensure(result["duration"]).is_less_than(max_time)
151
```
152
153
### Multiple Decorator Application
154
155
Apply multiple decorators to parameterized tests.
156
157
```python
158
from vedro import skip_if, only
159
160
# Apply multiple decorators to parameter sets
161
@params[(skip_if(not EXTERNAL_API_AVAILABLE), only)](
162
"external_api", "https://api.external.com"
163
)
164
@params("internal_api", "http://localhost:8000")
165
@scenario("API integration tests")
166
def test_api_integration(api_name, base_url):
167
168
@when(f"calling {api_name}")
169
def action():
170
return api_request(f"{base_url}/health")
171
172
@then("API responds successfully")
173
def verification(response):
174
ensure(response.status_code).equals(200)
175
```
176
177
## Types
178
179
### Parameterized
180
181
Internal class representing a parameterized test with arguments and decorators.
182
183
```python { .api }
184
class Parameterized:
185
"""
186
Represents a parameterized function or method with stored arguments
187
and decorators that are applied when the function is invoked.
188
"""
189
190
def __init__(self, args, kwargs, decorators: Tuple): ...
191
def __call__(self, fn: F) -> F: ...
192
```
193
194
### Type Annotations
195
196
For type checking support, params provides appropriate type annotations.
197
198
```python { .api }
199
# Type-checking support
200
F = TypeVar("F", bound=Callable[..., Any])
201
ItemType = Union[Callable[[F], F], Tuple[Callable[[F], F], ...]]
202
```
203
204
## Advanced Patterns
205
206
### Complex Parameter Objects
207
208
Use complex objects as parameters for comprehensive test scenarios:
209
210
```python
211
from dataclasses import dataclass
212
213
@dataclass
214
class UserProfile:
215
name: str
216
email: str
217
role: str
218
active: bool
219
220
@params(UserProfile("John Doe", "john@example.com", "admin", True))
221
@params(UserProfile("Jane Smith", "jane@example.com", "user", True))
222
@params(UserProfile("Bob Johnson", "bob@example.com", "guest", False))
223
@scenario("User profile management")
224
def test_user_profiles(profile):
225
226
@given("user profile data")
227
def setup():
228
return profile
229
230
@when("profile is processed")
231
def action(user_profile):
232
return process_user_profile(user_profile)
233
234
@then("profile is handled correctly")
235
def verification(result):
236
if profile.active:
237
ensure(result.status).equals("processed")
238
else:
239
ensure(result.status).equals("inactive")
240
```
241
242
### Parameter Generation
243
244
Generate parameters dynamically for data-driven tests:
245
246
```python
247
# Generate test parameters from external data
248
test_cases = [
249
params(input_val, expected)
250
for input_val, expected in load_test_data("math_operations.json")
251
]
252
253
# Apply generated parameters
254
for param_decorator in test_cases:
255
@param_decorator
256
@scenario("Generated math test")
257
def test_generated_math(input_val, expected):
258
@when("calculation is performed")
259
def action():
260
return complex_calculation(input_val)
261
262
@then("result matches expected value")
263
def verification(result):
264
ensure(result).equals(expected)
265
```
266
267
### Conditional Parameterization
268
269
Skip or modify parameters based on runtime conditions:
270
271
```python
272
import sys
273
274
# Conditionally apply parameters based on Python version
275
version_params = []
276
if sys.version_info >= (3, 9):
277
version_params.append(params("python39_feature", True))
278
if sys.version_info >= (3, 10):
279
version_params.append(params("python310_feature", True))
280
281
version_params.append(params("legacy_feature", True))
282
283
for param_decorator in version_params:
284
@param_decorator
285
@scenario("Version-specific features")
286
def test_version_features(feature_name, should_work):
287
@when(f"using {feature_name}")
288
def action():
289
return test_feature(feature_name)
290
291
@then("feature works as expected")
292
def verification(result):
293
ensure(result.success).equals(should_work)
294
```