How to Use Indirect Parametrize in pytest for Flexible Testing
In pytest, use
@pytest.mark.parametrize with the indirect=True option to pass parameters to fixtures instead of directly to test functions. This lets fixtures receive and process parameters before the test runs, enabling more flexible setup and reuse.Syntax
The @pytest.mark.parametrize decorator is used with the indirect=True argument to tell pytest to send the parameter values to the fixture instead of the test function directly.
Syntax parts explained:
argnames: The name(s) of the parameter(s) as string(s).argvalues: A list of values to pass.indirect=True: Tells pytest to treat the parameters as inputs to fixtures.
python
@pytest.mark.parametrize('param', [value1, value2], indirect=True) def test_example(param): # test code using fixture 'param' pass
Example
This example shows how to use indirect parametrize to pass different strings to a fixture that processes them before the test runs.
python
import pytest @pytest.fixture def data(request): # Fixture receives parameter via request.param return request.param.upper() @pytest.mark.parametrize('data', ['hello', 'world'], indirect=True) def test_uppercase(data): assert data.isupper() assert isinstance(data, str)
Output
============================= test session starts ==============================
collected 2 items
test_example.py .. [100%]
============================== 2 passed in 0.03s ===============================
Common Pitfalls
Common mistakes when using indirect parametrize include:
- Not setting
indirect=True, so parameters go directly to the test, causing errors if the test expects a fixture. - Using
indirect=Truewithout a matching fixture name, leading to pytest errors. - Trying to indirect parametrize multiple arguments without specifying which ones are indirect.
Correct usage requires matching the parameter name to a fixture and setting indirect=True properly.
python
import pytest @pytest.fixture def number(request): return request.param * 2 # Wrong: missing indirect=True @pytest.mark.parametrize('number', [1, 2]) def test_wrong(number): # This will fail because 'number' is not processed by fixture assert number % 2 == 0 # Right: with indirect=True @pytest.mark.parametrize('number', [1, 2], indirect=True) def test_right(number): assert number % 2 == 0
Output
============================= test session starts ==============================
collected 2 items
test_example.py F. [100%]
=================================== FAILURES ===================================
______________________________ test_wrong[1] ________________________________
number = 1
def test_wrong(number):
> assert number % 2 == 0
E assert 1 % 2 == 0
E + where 1 = number
test_example.py:11: AssertionError
============================== 1 failed, 1 passed in 0.04s ======================
Quick Reference
Summary tips for using indirect parametrize in pytest:
- Use
indirect=Trueto pass parameters to fixtures. - Parameter names must match fixture names.
- You can indirect parametrize multiple fixtures by passing a list to
indirect. - Fixtures receive parameters via
request.param.
| Feature | Description |
|---|---|
| @pytest.mark.parametrize | Decorator to define test parameters |
| indirect=True | Send parameters to fixtures instead of test function |
| request.param | Access parameter inside fixture |
| Matching names | Parameter name must match fixture name |
| Multiple indirect | Use indirect=["arg1", "arg2"] for multiple fixtures |
Key Takeaways
Use @pytest.mark.parametrize with indirect=True to pass parameters to fixtures.
Fixture names must match the parameter names for indirect parametrization to work.
Access the parameter inside the fixture with request.param.
Without indirect=True, parameters go directly to the test function, causing errors if a fixture is expected.
You can indirect parametrize multiple fixtures by passing a list to the indirect argument.