基于命令行开关进行pytest fixture参数化的更干净的方法



从技术上讲,我已经解决了我正在处理的问题,但我忍不住觉得我的解决方案很糟糕:

我有一个pytest套件,可以在两种模式下运行:本地模式(用于开发测试;一切都只通过Chrome在我的开发框上运行)和串行面回归测试模式(用于CI;该套件可以在无数浏览器和操作系统上运行)。我有一个命令行标志可以在两种模式之间切换,--test-local。如果它在那里,我以本地模式运行。如果它不在那里,我会以严肃的面部模式运行。我是这样做的:

# contents of conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption("--test-local", action="store_true", default=False, help="run locally instead of in seriousface mode")
def pytest_generate_tests(metafunc):
if "dummy" in metafunc.fixturenames:
if metafunc.config.getoption("--test-local"):
driverParams = [(True, None)]
else:
driverParams = [(False, "seriousface setting 1"), (False, "seriousface setting 2")]
metafunc.parameterize("dummy", driverParams)
@pytest.fixture(scope="function")
def driver(dummy):
_driver = makeDriverStuff(dummy[0], dummy[1])
yield _driver
_driver.cleanup()
@pytest.fixture
def dummy():
pass

问题是,dummy固定装置太可怕了。我已经尝试过让pytest_generate_tests直接参数化driver夹具,但它最终替换了夹具,而不仅仅是向其中添加内容,所以测试结束时cleanup()永远不会被调用。使用dummy可以将dummy替换为参数元组,从而将其传递到driver()中。

但是,重申一下,我所拥有的确实有效,它只是感觉像一个janky破解。

您可以尝试一种不同的方法:不是为测试动态选择参数集,而是在上面声明所有参数集,但在启动时取消选择不相关的参数集。

# r.py
import pytest
real = pytest.mark.real
mock = pytest.mark.mock
@pytest.mark.parametrize('a, b', [
real((True, 'serious 1')),
real((True, 'serious 2')),
mock((False, 'fancy mock')),
(None, 'always unmarked!'),
])
def test_me(a, b):
print([a, b])

然后按如下方式运行:

pytest -ra -v -s   r.py -m real        # strictly marked sets
pytest -ra -v -s   r.py -m mock        # strictly marked sets
pytest -ra -v -s   r.py -m 'not real'  # incl. non-marked sets
pytest -ra -v -s   r.py -m 'not mock'  # incl. non-marked sets

此外,skipif标记可用于所选参数集(与取消选择不同)。pytest本机支持它们。但是语法很难看。请参阅pytest的Skip/xfail with parameterize部分中的更多内容。

官方手册还包含与您在自定义标记和命令行选项中的问题完全相同的情况,以控制测试运行。然而,它也不如-m测试取消选择那么优雅,更适合复杂的运行时条件,而不是基于先验的已知测试结构。

相关内容

  • 没有找到相关文章

最新更新