根据选项/配置动态参数化 Pytest 夹具

问题描述 投票:0回答:3

我有一个基本的 Pytest 测试套件正在运行,我需要在运行时根据配置/参数动态参数化固定装置。

我的测试套件的“核心”是一个会话范围的固定装置,它根据一些自定义 CLI 参数执行一些“非常”昂贵的初始化,并且所有测试都使用此固定装置。稍微简单一点,将夹具视为提供到服务器的远程连接以运行测试,初始化涉及配置该服务器上的操作系统/依赖项(因此它昂贵且仅限会话范围),并且 CLI 参数指定操作系统/环境配置方面。 这对于单独的测试运行非常有用,但现在我想使用这个测试套件并在一系列不同的测试配置上运行整个测试。配置列表需要在运行时根据配置文件和一些附加 CLI 参数确定。

据我了解,在 Pytest 中执行此类操作的“明显”方法是参数化我的初始化装置。但问题是我需要根据其他参数动态地执行此操作;看起来您可以调用一个函数来填充

params

中的

@pytest.fixture
列表,但该函数无法访问 Pytest CLI 参数,因为参数解析尚未发生。
我已经设法弄清楚如何通过实现

pytest_generate_tests

来使用

间接
参数化动态参数化每个测试,并利用夹具缓存来确保每个唯一的夹具配置实际上只初始化一次,即使实际上,每次测试都会对夹具进行参数化。这是可行的,尽管 Pytest 是否正式支持这一点值得怀疑。有没有更好的方法来实现我在这里想做的事情?

“正确”的方式

def generate_parameters(): # This is just a plain function, and arg parsing hasn't happened yet, # so I can't use Pytest options to generate my parameters pass @pytest.fixture(scope="session", params=generate_parameters()) def expensive_init_fixture(pytestconfig, request): # Do initialization based on CLI args and request.param pass

工作方式

@pytest.fixture(scope="session") def expensive_initialization_fixture(pytestconfig, request): # Do initialization based on CLI args and request.param pass def pytest_generate_tests(metafunc): if 'expensive_init_fixture' in metafunc.fixturenames: parameters = [] # Generate parameters based on config in metafunc.config metafunc.parametrize('expensive_init_fixture', parameters, scope="session", indirect=True)

	
python pytest
3个回答
0
投票
pytest_testconfig

听起来是一个不错的解决方案。 testconfig 允许您在所有测试中使用全局配置变量,您可以根据需要设置它们的值,这意味着您可以从 CLI 获取它们。 这意味着您在开始运行时可以使用 config 的默认值,如果您想在下次运行中更改它,您可以从 CLI 获取参数。

我不确定他们背后的动机是什么,但你应该看看你是否真的需要一个 global_config.py 文件,在运行之间更改测试值不应该是可以从 CLI 配置的,测试应该是持久的,并且如果某些内容需要更改,那么提交是一个更好的解决方案,因为您可以看到它的历史记录。


0
投票

我需要在配置选项关闭时生成特定参数,并在配置选项打开时将其他值添加到参数集中。并且基本上不会一直生成所有测试变体,而是仅在合适时生成所有测试变体,而不是生成所有测试并在不满足条件时跳过它们。

我能想到的回避这个问题的唯一方法是使用环境参数将数据传递给 pytest,即类似:

ENABLE_IT=True pytest ...

然后在里面使用第一种方法,但是

os.environ.get('ENABLE_IT', 'False')

虽然很难看,但可以用。快问。当您使用 
--collect-only

调用 pytest 时,您的工作解决方案是否正确显示测试名称,或者您不关心这一点?


0
投票

效果很好。

在conftest.py中:

import pytest def pytest_addoption(parser: pytest.Parser): parser.addoption("--python", type=str, default="3.12", help="Run integration tests with these versions of python") def pytest_configure(config: pytest.Config): pythons = config.option.python.split() class AllPython: @pytest.fixture(scope="session", params=pythons) def python_version(self, request: pytest.FixtureRequest): "python major version(s) to use" return request.param config.pluginmanager.register(AllPython())

您可以在
pytest_configure

中根据需要动态创建“插件类”。这意味着您可以根据需要完全动态地计算参数列表。

    

© www.soinside.com 2019 - 2024. All rights reserved.