在 pytest skip-if 条件中使用命令行选项

klr*_*her 7 python pytest

长话短说,如果会话是针对我们的生产 API 运行的,我希望能够跳过一些测试。运行测试的环境是使用命令行选项设置的。

我想到了使用pytest_namespace来跟踪全局变量的想法,所以我在我的 conftest.py 文件中进行了设置。

def pytest_namespace():
    return {'global_env': ''}
Run Code Online (Sandbox Code Playgroud)

我接受命令行选项并在 conftest.py 的夹具中设置各种 API url(来自 config.ini 文件)。

@pytest.fixture(scope='session', autouse=True)
def configInfo(pytestconfig):
    global data
    environment = pytestconfig.getoption('--ENV')
    print(environment)
    environment = str.lower(environment)

    pytest.global_env = environment

    config = configparser.ConfigParser()
    config.read('config.ini') # local config file
    configData = config['QA-CONFIG']
    if environment == 'qa':
            configData = config['QA-CONFIG']
    if environment == 'prod':
            configData = config['PROD-CONFIG']

(...)
Run Code Online (Sandbox Code Playgroud)

然后我有了我想跳过的测试,它是这样装饰的:

@pytest.mark.skipif(pytest.global_env in 'prod',
                reason="feature not in Prod yet")
Run Code Online (Sandbox Code Playgroud)

但是,每当我针对 prod 运行测试时,它们都不会被跳过。我做了一些摆弄,发现:

a) global_env 变量可以通过另一个夹具访问

@pytest.fixture(scope="session", autouse=True)
def mod_header(request):
    log.info('\n-----\n| '+pytest.global_env+' |\n-----\n')
Run Code Online (Sandbox Code Playgroud)

在我的日志中正确显示

b) global_env 变量可在测试中访问,正确记录环境。

c)pytest_namespace已弃用

所以,我假设这与 skipif 何时访问 global_env 与夹具在测试会话中何时访问有关。我还发现使用已弃用的功能并不理想。

我的问题是:

  • 如何从 pytest 命令行选项中获取值到 skipif 中?
  • 有没有比 更好的方法来尝试这个pytest_namespace

Мак*_*тов 8

看起来像根据命令行选项控制跳过测试的真正方法是将测试动态标记为跳过

  1. 使用pytest_addoption钩子添加选项,如下所示:
def pytest_addoption(parser):
    parser.addoption(
        "--runslow", action="store_true", default=False, help="run slow tests"
    )
Run Code Online (Sandbox Code Playgroud)
  1. 使用pytest_collection_modifyitems钩子添加这样的标记:
def pytest_collection_modifyitems(config, items):
    if config.getoption("--runslow"):
        # --runslow given in cli: do not skip slow tests
        return
    skip_slow = pytest.mark.skip(reason="need --runslow option to run")
    for item in items:
        if "slow" in item.keywords:
            item.add_marker(skip_slow)
Run Code Online (Sandbox Code Playgroud)
  1. 为您的测试添加标记:
@pytest.mark.slow
def test_func_slow():
    pass
Run Code Online (Sandbox Code Playgroud)

如果您想在测试中使用来自 CLI 的数据,例如,它的凭据,足以在从pytestconfig检索它们时指定跳过选项

  1. 使用pytest_addoption钩子添加选项,如下所示:
def pytest_addoption(parser):
    parser.addoption(
        "--credentials",
        action="store",
        default=None,
        help="credentials to ..."
    )
Run Code Online (Sandbox Code Playgroud)
  1. 从 pytestconfig 获取时使用跳过选项
@pytest.fixture(scope="session")
def super_secret_fixture(pytestconfig):
    credentials = pytestconfig.getoption('--credentials', skip=True)
    ...
Run Code Online (Sandbox Code Playgroud)
  1. 像往常一样在测试中使用夹具:
def test_with_fixture(super_secret_fixture):
    ...
Run Code Online (Sandbox Code Playgroud)

在这种情况下,你会得到这样的东西,你不会向--credentialsCLI发送选项:

Skipped: no 'credentials' option found
Run Code Online (Sandbox Code Playgroud)

最好使用_pytest.config.get_config而不是不推荐使用的pytest.config如果您仍然不会像这样使用pytest.mark.skipif

@pytest.mark.skipif(not _pytest.config.get_config().getoption('--credentials'), reason="--credentials was not specified")
Run Code Online (Sandbox Code Playgroud)

  • 我觉得令人困惑的是,根据 pytest 的[历史笔记](https://docs.pytest.org/en/latest/historical-notes.html#string-conditions),用户过去只需正如答案末尾提到的一行,使用“pytest.mark.skipif(pytest.config.getoption(...))”,现在他们必须跳过十亿个圈并使用“modifyitems”钩子。当他们弃用“pytest.config”时,他们应该为“skipif”依赖于配置选项的这种常见用例提供一个类似简洁且官方支持(即不是基于“_pytest”)的替代方案。 (5认同)
  • 对我来说奇怪的是,“pytest”对此的官方答案是自己实现一个“--runslow”标志。我觉得测试过程中固有的,你总是会有一些长时间运行的、smoketest-y 类型的测试,你可能想默认跳过这些测试,如果内置了 --runslow 会很好。 (2认同)