Pytest:如何确保首先调用某个夹具 [英] Pytest: How to make sure a certain fixture is called first

查看:70
本文介绍了Pytest:如何确保首先调用某个夹具的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 a_file 中有一些数据,我需要用它们来参数化我的装置.因此,我编写了一个辅助函数,它返回用文件中的数据填充的 a_list.现在我可以通过 @pytest.fixture(params=a_list) 轻松地参数化我的装置.看起来很直接,对吗?

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?

这里的问题是 a_file 是由另一个夹具生成的,似乎 pytest 在夹具实际创建文件之前调用了依赖于该文件的帮助程序.由于这种行为,会引发 FileNotFoundError.

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.

我的代码如下所示:

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

附加:create_file_fixture需要是一个fixture,不能转换成普通函数,因为它依赖于其他fixture.

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.

显而易见的解决方案是确保在执行需要文件的辅助函数之前创建文件.

The obvious solution is to make sure that the file gets created before the helper function which needs the file gets executed.

所以我

  • create_file_fixture 的依赖项添加到应该像这样参数化的夹具中:

  • 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

  • autouse 标志添加到创建文件的夹具中,如下所示:

  • 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
    

  • 但 pytest 仍然首先调用辅助函数,这会导致与上述相同的错误.

    but pytest still calls the helper functions first which results in the same error as described above.

    如何确保先执行 create_file_fixture?

    我认为一个可能的解决方案是将辅助函数也转换为夹具.因此,我可以轻松地在那里添加依赖项,该依赖项将指示 pytest 应以何种顺序执行夹具.这看起来像这样:

    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.

    推荐答案

    该错误不是由 pytest 引起的.这是因为当模块被 Python 解释器加载时,你的辅助函数被调用,名义上是在它进入 pytest 之前.

    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.

    不幸的是,你不能从一个装置中产生一个以上的值,并且你不能对惰性生成器进行参数化.原因是必须在运行任何装置或测试之前计算完整图,这意味着预先知道所有参数,如 此失败的功能请求.@Hoefling 的评论 建议一种解决此问题的方法.我会建议一种可能不那么 pytest-thonic,但仍然可以工作的方法.

    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
    

    我认为让 create_file_function 返回文件名更优雅/可配置.

    I think it is a bit more elegant/configurable to have create_file_function return the name of the file.

    给定 a_file 看起来像:

    ABC
    DEF
    

    pytest -v 的输出如下所示:

    ============================= 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 ===========================
    

    这篇关于Pytest:如何确保首先调用某个夹具的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆