I want to parametrize a test with a list which is created dynamically by a fixture like so:
@pytest.fixture
def my_list_returning_fixture(depends_on_other_fixtures):
return ["a dynamically created list which", depends_on_other_fixtures]
How can I achieve that? Alternatively, how can I ensure that a certain fixture gets called first - this would solve this problem before it even occurs.
I tried to parametrize the test with the fixture (which just results in errors because python thinks I want to hand over the function itself):
@pytest.mark.parametrize(
"an_element_from_the_list_of_my_fixture",
my_list_returning_fixture
)
def test_the_list(an_element_from_the_list_of_my_fixture):
print(an_element_from_the_list_of_my_fixture)
Calling the fixture like a normal function like my_list_returning_fixture()
just results in errors, too! Python doesn't know how to fill the "parameters" of the fixture (which are actually just other fixtures) and displays an error message about too few passed arguments...
Therefore I need pytest to inject the depends_on_other_fixtures
dependencies, so I can't call it like a normal function.
I also tried to interpose another fixture between the list fixture and the test like so:
@pytest.fixture(params=my_list_returning_fixture)
def my_interposed_parametrized_fixture(request):
return request.param
def test_the_list(my_interposed_parametrized_fixture):
...
I also tried to play around with indirect parametrization but it didn't work either...
I know it is easily possible to parametrize a test with a given list
like so:
the_list = [1, 2, 3]
@pytest.mark.parametrize("an_element_from_the_list", the_list)
def test_the_list(an_element_from_the_list):
print(an_element_from_the_list)
This will lead to three tests. One for each element in the list.
You can use such a simple parametrized fixture for more complex fixtures by combining the param value with some kind of factory. You can also alias the call to parametrize: numbers = pytest.
parametrize allows one to define multiple sets of arguments and fixtures at the test function or class.
you can put @pytest. mark. parametrize style parametrization on the test functions to parametrize input/output values as well.
This seems to be a duplicate of this question.
By design, this is not possible: the concept of "fixtures" is reserved to test execution, while the concept of "parameters" is reserved to test collection. Please see my detailed answer here.
The short answer is that you can't do it the way you want, i.e., through fixtures: https://github.com/pytest-dev/pytest/issues/2155. Basically, the number of things yielded or returned has to be known up front for pytest to properly compute the fixture and test dependency graph.
It appears that the only way is to fix the list elements before passing them to any of pytests's decorators. Here is an example, related to your other question, showing that the problem can not be solved by say a generator:
import pytest
def gen_lines():
with open('file_that_does_not_exist') as f:
yield from f
@pytest.fixture(scope='session')
def create_file():
with open('file_that_does_not_exist', 'w') as f:
print('ABC', file=f)
print('DEF', file=f)
@pytest.fixture(params=gen_lines())
def line_fixture(request):
return request.param
def test_line(line_fixture):
assert True
This will fail at collection time when pytest turns your generator into a list. Adding a dependency to line_fixture
on create_file
won't help either for the same reason.
Your only real option at this point is to run create_file
at module load time or before.
import pytest
def gen_lines():
with open('file_that_does_not_exist') as f:
yield from f
def create_file():
with open('file_that_does_not_exist', 'w') as f:
print('ABC', file=f)
print('DEF', file=f)
create_file()
@pytest.fixture(params=gen_lines())
def line_fixture(request):
return request.param
def test_line(line_fixture):
assert True
The list does not have to be static per-se. It just can't be created by a fixture. But don't let that stop you. You can put the code for defining and running create_file
into a separate module, and just import it wherever you need it as a utility. That will obscure all the messy details and make your code look about as clean as it would with fixtures.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With