【问题标题】:How can I dynamically generate pytest parametrized fixtures from imported helper methods?如何从导入的辅助方法动态生成 pytest 参数化装置?
【发布时间】:2022-12-10 09:21:57
【问题描述】:

我想要实现的基本上是this,但是有一个类范围的、参数化的夹具。

问题是,如果我从辅助文件导入方法 (generate_fixture and inject_fixture),注入夹具代码似乎被调用得太晚了。这是一个完整的工作代码示例:

# all of the code in one file
import pytest
import pytest_check as check

def generate_fixture(params):
    @pytest.fixture(scope='class', params=params)
    def my_fixture(request, session):
        request.cls.param = request.param
        print(params)

    return my_fixture

def inject_fixture(name, someparam):
    globals()[name] = generate_fixture(someparam)

inject_fixture('myFixture', 'cheese')

@pytest.mark.usefixtures('myFixture')
class TestParkingInRadius:

    def test_custom_fixture(self):
        check.equal(True, self.param, 'Sandwhich')

如果我将 generate 和 inject helpers 移动到它们自己的文件中(根本不改变它们),我会得到一个 fixture not found 错误,即如果测试文件看起来像这样:

import pytest
import pytest_check as check

from .helpers import inject_fixture

inject_fixture('myFixture', 'cheese')

@pytest.mark.usefixtures('myFixture')
class TestParkingInRadius:

    def test_custom_fixture(self):
        check.equal(True, self.param, 'Sandwhich')

我在设置时遇到错误:E fixture 'myFixture' not found,后跟可用装置列表(不包括注入的装置)。

有人可以帮助解释为什么会这样吗?必须在每个单独的测试文件中定义这些函数有点违背了这样做的全部意义(让事情保持干燥)。

【问题讨论】:

  • 这实际上应该有效,至少与夹具相关的部分(我不知道 session 夹具是什么,以及代码中是否还有其他可能有问题的地方)。如果我只是使用您链接到的示例并对其进行调整以添加params 并使用mark.usefixtures 它工作正常,所以我不确定您的代码的哪一部分有问题。我建议您首先创建一个最小的可重现示例并调整问题(如果您在执行此操作时没有发现问题)。
  • 感谢@MrBeanBremen 的输入——这让我走上了正确的道路。我现在已经确定了错误的原因并相应地更新了问题和标题:)

标签: dynamic pytest python-import fixtures parametrized-testing


【解决方案1】:

我解决了这个问题。

将 inject fixture 方法放在不同的文件中会更改该方法的全局范围。它在同一个文件中工作的原因是调用者和注入夹具方法共享相同的全局范围。

使用本机检查包并获取调用者的范围解决了这个问题,这里是完整的样板工作代码,包括通过内置的request夹具进行类内省:

import inspect
import pytest

def generate_fixture(scope, params):
    @pytest.fixture(scope=scope, params=params)
    def my_fixture(request):
        request.cls.param = request.param
        print(request.param)

    return my_fixture

def inject_fixture(name, scope, params):
    """Dynamically inject a fixture at runtime"""
    # we need the caller's global scope for this hack to work hence the use of the inspect module
    caller_globals = inspect.stack()[1][0].f_globals
    # for an explanation of this trick and why it works go here: https://github.com/pytest-dev/pytest/issues/2424
    caller_globals[name] = generate_fixture(scope, params)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 2014-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多