Pytest: How to make sure a certain fixture is called first

断了今生、忘了曾经 提交于 2019-12-12 13:47:34

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!