首页 > 解决方案 > Pytest 动态夹具范围 - 如何设置夹具范围并将其应用于所有测试?

问题描述

我正在尝试使用 pytest 固定装置动态范围。文档声明范围将在夹具定义期间确定;这是否意味着一旦在 pytest run 中动态设置范围,此范围将适用于使用该夹具的所有测试?是否可以在测试运行期间影响范围(即使用标记)?如果没有,我该如何更改配置(不使用命令行 arg)来更改范围?

我尝试添加一个标记并将其值用作 pytest_generate_tests 中的范围,但是夹具定义在 pytest_generate_tests 之前运行。

def pytest_generate_tests(metafunc):
    fixture_scope = metafunc.definition.get_closest_marker('scope').args
    if fixture_scope is not None:
        metafunc.config.addinivalue_line('markers', f'scope:{fixture_scope[0]}')


def determine_scope(fixture_name, config):
    scope = [i for i in config.getini('markers') if 'scope' in i][0]
    if scope:
        return scope.split(':')[-1]
    return "function"


@pytest.fixture(scope=determine_scope)
def some_fixture():

标签: pytest

解决方案


我建议使用 env var 作为范围。如果要更改范围,请更改 env var。范围更改只会在夹具的当前范围结束后生效。

@pytest.fixture(scope=os.environ.get("fixture_scope","function))
def fixture_name():
    pass

def test_change_fixture():
    os.environ["fixture_scope"] = "class"

我没有测试过这段代码。但我发现使用 env var 在 pytest 运行的不同阶段之间传递变量非常有用。您还可以使用动态配置文件或类似的东西。

实现这一目标的一种丑陋方法是拥有 4 个相同夹具的副本并根据需要获取相关夹具。

def fixture_code():
    pass

@pytest.fixture(scope="module)
def module_fixture():
    fixture_code()

@pytest.fixture(scope="session")
def session_fixture():
    fixture_code()

# similar fixtures for other scopes

@pytest.fixture(scope="session")
def fixture_provider(request, module_fixture, session_fixture, .....):
    if request.param['scope'] == "module":
       return module_fixture
    elif request.param['scope'] == "session":
       return session_fixture
    .
    .
    .

@pytest.mark.parametrize("scope",[os.environ.get("fixture_scope")], indirect=True)
def test_abc(fixture_provider):
   #use fixture provider.

您可以使用代码设置 env var 以获取相关夹具。


推荐阅读