An optional parameter to the fixture decorator is params
.
For each value in params, the fixture will be called with request.param
filled in with that value.
Tests that use the fixture will be called once FOR EACH value in params
.
Toy example
An example is in order here.
This first example is a silly one, but does show the mechanics, and the utility of both the -v flag and how well pytest deals with failures of parameterized tests.
import pytest
@pytest.fixture(params=[1,2,3])
def some_data(request):
return request.param
def test_not_2(some_data):
assert some_data != 2
def test_less_than_4(some_data):
assert some_data < 4
This should run both tests three times each, and fail “test_not_2” when 2 is passed in.
I’m using -v
so we can see both the test name, and the parameter passed in.
And also --tb=no
because some_dta != 2
is not really an interesting traceback.
$ pytest -v --tb=no test_params.py
================== test session starts ==================
collected 6 items
test_params.py::test_not_2[1] PASSED [ 16%]
test_params.py::test_not_2[2] FAILED [ 33%]
test_params.py::test_not_2[3] PASSED [ 50%]
test_params.py::test_less_than_4[1] PASSED [ 66%]
test_params.py::test_less_than_4[2] PASSED [ 83%]
test_params.py::test_less_than_4[3] PASSED [100%]
================ short test summary info ================
FAILED test_params.py::test_not_2[2] - assert 2 != 2
============== 1 failed, 5 passed in 0.05s ==============
I wanted to show you a failing example just to show that pytest continues the rest of the parameter values, even if one fails.
Scope effect on parametrization
In the above example, we used the default “function” scope.
With parametrization of fixtures, that means the first test ran through all values of the fixture, before moving on to the next test.
If we change to “module” scope, we’ll see a different order:
So change the code as follows:
@pytest.fixture(params=[1,2,3], scope="module")
def some_data(request):
return request.param
Now, we run through each test using the fixture, then move on to the next value and repeat:
$ pytest -v --tb=no test_params.py
================== test session starts ==================
collected 6 items
test_params.py::test_not_2[1] PASSED [ 16%]
test_params.py::test_less_than_4[1] PASSED [ 33%]
test_params.py::test_not_2[2] FAILED [ 50%]
test_params.py::test_less_than_4[2] PASSED [ 66%]
test_params.py::test_not_2[3] PASSED [ 83%]
test_params.py::test_less_than_4[3] PASSED [100%]
================ short test summary info ================
FAILED test_params.py::test_not_2[2] - assert 2 != 2
============== 1 failed, 5 passed in 0.05s ==============
This is super handy if the setup/teardown of the fixture is doing some time consuming work per param value.
This post is part of a series on pytest fixtures
- pytest fixtures nuts and bolts
- pytest xunit-style fixtures
- Basic pytest fixtures example
- Using pytest fixtures by naming them
- Using pytest autouse fixtures
- Using pytest fixtures with mark.usefixtures
- pytest fixture return value
- pytest fixture teardown
- pytest fixture scope
- Parametrizing pytest fixtures with param - this post
- Using multiple pytest fixtures
- Modularity: pytest fixtures using other fixtures
- pytest session scoped fixtures
- Mixing pytest fixture scope)