简体   繁体   English

基于命令行开关进行 pytest 夹具参数化的更简洁方法?

[英]Cleaner way to do pytest fixture parameterization based on command-line switch?

I've technically already solved the problem I was working on, but I can't help but feel like my solution is ugly:从技术上讲,我已经解决了我正在解决的问题,但我不禁觉得我的解决方案很丑陋:

I've got a pytest suite that I can run in two modes: Local Mode (for developing tests; everything just runs on my dev box through Chrome), and Seriousface Regression Testing Mode (for CI; the suite gets run on a zillion browsers and OSes).我有一个 pytest 套件,我可以在两种模式下运行:本地模式(用于开发测试;一切都通过 Chrome 在我的开发箱上运行)和 Seriousface 回归测试模式(用于 CI;该套件在无数浏览器上运行和操作系统)。 I've got a command-line flag to toggle between the two modes, --test-local .我有一个命令行标志可以在两种模式之间切换, --test-local If it's there, I run in local mode.如果它在那里,我在本地模式下运行。 If it's not there, I run in seriousface mode.如果它不在那里,我会以严肃模式运行。 Here's how I do it:这是我的方法:

# 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

The problem is, that dummy fixture is hideous.问题是,那个dummy夹具太可怕了。 I've tried having pytest_generate_tests parameterize the driver fixture directly, but it ends up replacing the fixture rather than just feeding stuff into it, so cleanup() never gets called when the test finishes.我试过让pytest_generate_tests直接参数化driver装置,但它最终替换了装置,而不仅仅是将东西放入其中,因此在测试完成时永远不会调用cleanup() Using the dummy lets me replace the dummy with my parameter tuple, so that that gets passed into driver() .使用 dummy 可以让我用我的参数元组替换 dummy,以便将其传递给driver()

But, to reiterate, what I have does work , it just feels like a janky hack.但是,重申一下,我所拥有的确实有效,感觉就像是一个笨拙的黑客。

You can try a different approach: instead of dynamically selecting the parameter set for the test, declare ALL parameter sets on it, but deselect the irrelevant ones at launch time.您可以尝试不同的方法:不是为测试动态选择参数集,而是在其上声明所有参数集,但在启动时取消选择不相关的参数集。

# 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])

Then run it as follows:然后按如下方式运行它:

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

Also, skipif marks can be used for the selected parameter set (different from deselecting).此外, skipif标记可用于选定的参数集(与取消选择不同)。 They are natively supported by pytest.它们由 pytest 原生支持。 But the syntax is quite ugly.但是语法非常难看。 See more in the pytest's Skip/xfail with parametrize section.在 pytest 的带参数化部分的Skip/xfail 中查看更多信息。

The official manual also contains exactly the same case as in your question in Custom marker and command line option to control test runs .官方手册还包含与您在Custom marker and command line option to control test running中的问题完全相同的案例。 However, it is also not as elegant as -m test deselection, and is more suitable for complex run-time conditions, not on the apriori known structure of the tests.但是,它也没有-m test 取消选择那么优雅,更适合复杂的运行时条件,而不是先验已知的测试结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM