问题
I have some data in a_file
which I need to parametrize my fixture with. Therefore, I wrote a helper function which returns a_list
filled with the data from the file. Now I can easily parametrize my fixture via @pytest.fixture(params=a_list)
. Seems straight forward, right?
The problem here is that a_file
is generated by another fixture and it seems that pytest calls the helper which relies on that file before the file gets actually created by the fixture. Due to that behavior, a FileNotFoundError
is raised.
My code looks like this:
def helper_returning_list_from_a_file():
with open("a_file") as a_file:
a_list = a_file.readlines()
return a_list
@pytest.fixture(scope="session")
def create_file_fixture(depends_on_other_fixtures):
# create "a_file" here
@pytest.fixture(params=helper_returning_list_from_a_file())
def a_fixture_which_is_parametrized_with_data_from_a_file(request):
return request.param
def test_which_uses(a_fixture_which_is_parametrized_with_data_from_a_file):
assert False
Addition: The create_file_fixture
needs to be a fixture and can't be transformed to a normal function because it depends on other fixtures.
What I already tried
The obvious solution is to make sure that the file gets created before the helper function which needs the file gets executed.
Therefore I
added a dependency for
create_file_fixture
to the fixture which should get parametrized like so:@pytest.fixture(params=helper_returning_list_from_a_file()) def a_fixture_which_is_parametrized_with_data_from_a_file(create_file_fixture, request): return request.param
added the
autouse
flag to the fixture which creates the file like so:@pytest.fixture(scope="session", autouse=True) def create_file_fixture: # create "a_file" here
but pytest still calls the helper functions first which results in the same error as described above.
Question
How can I ensure that the create_file_fixture
is executed first?
Possible solution
I think a possible solution would be to transform the helper function to a fixture, too. So I could easily add the dependency there which would dictate to pytest in which order the fixtures should be executed. This would look like so:
@pytest.fixture()
def fixture_returning_list_from_a_file(create_file_fixture):
with open("a_file") as a_file:
a_list = a_file.readlines()
return a_list
This would solve my problem that the file doesn't exist but this also doesn't work for me because it leads to another problem which I described here: parametrizing a test with a list returned from a fixture.
回答1:
The error is not caused by pytest
as such. It is caused by the fact that your helper function is called when the module is loaded by the Python interpreter, nominally before it gets to pytest.
Unfortunately, you can't yield more than one value from a fixture, and you can't parametrize over a lazy generator. The reason is that the full graph has to be computed before any fixtures or tests are run, which means knowing all the parameters up front, as explained in this failed feature request. @Hoefling's comment suggests one way to work around this. I would suggest a way that is probably less pytest-thonic, but should work nevertheless.
To ensure that your file is created up-front and that the entire list is available for parametrization, don't make it a fixture: just run it as part of your module loading code and make the list a module attribute. This won't prevent you from using it elsewhere. If multiple test modules use the same list, you can just place it into a separate non-test module and import it into the tests that need it.
def create_file_function():
# create "a_file" here
return 'a_file'
def helper_returning_list_from_a_file():
with open(create_file_function()) as a_file:
a_list = a_file.readlines()
return a_list
a_list = helper_returning_list_from_a_file()
@pytest.fixture(params=a_list)
def a_fixture_which_is_parametrized_with_data_from_a_file(request):
return request.param
def test_which_uses(a_fixture_which_is_parametrized_with_data_from_a_file):
assert False
I think it is a bit more elegant/configurable to have create_file_function
return the name of the file.
Given a_file
that looks like:
ABC
DEF
The output of pytest -v
looks like this:
============================= test session starts ==============================
platform linux -- Python 3.6.4, pytest-3.4.2, py-1.5.2, pluggy-0.6.0 -- /...
cachedir: .pytest_cache
rootdir: /..., inifile:
plugins: remotedata-0.2.0, pep8-1.0.6, openfiles-0.2.0, doctestplus-0.1.2, arraydiff-0.2
collected 2 items
52765085.py::test_which_uses[ABC\n] PASSED [ 50%]
52765085.py::test_which_uses[DEF] PASSED [100%]
=========================== 2 passed in 0.01 seconds ===========================
来源:https://stackoverflow.com/questions/52765085/pytest-how-to-make-sure-a-certain-fixture-is-called-first