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



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

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

def pytest_namespace():
return {'global_env': ''}

我采用命令行选项并在 conftest.py 的夹具中设置各种 API URL(来自配置.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']
(...)

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

@pytest.mark.skipif(pytest.global_env in 'prod',
reason="feature not in Prod yet")

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

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

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

在我的日志中正确显示

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

c(pytest_namespace已弃用

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

我的问题是:

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

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

  1. 使用pytest_addoption钩子添加选项,如下所示:
def pytest_addoption(parser):
parser.addoption(
"--runslow", action="store_true", default=False, help="run slow tests"
)
  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)
  1. 将标记添加到测试中:
@pytest.mark.slow
def test_func_slow():
pass

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

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

在这种情况下,您将获得类似的东西,您不会--credentials选项发送到 CLI:

Skipped: no 'credentials' option found

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

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

将全局代码放入灯具的问题在于,标记是在夹具之前评估的,因此当评估skipif时,configInfo尚未运行,pytest.global_env将为空。我建议将配置代码从夹具移动到pytest_configure钩子:

# conftest.py
import configparser
import pytest

def pytest_addoption(parser):
parser.addoption('--ENV')

def pytest_configure(config):
environment = config.getoption('--ENV')
pytest.global_env = environment
...

保证在收集测试和评估标记之前执行配置挂钩。

有没有比pytest_namespace更好的方法来尝试这个?

我知道的一些方法:

  1. 只需在pytest_configure中分配一个模块变量(pytest.foo = 'bar',就像我在上面的例子中所做的那样(。
  2. 使用在整个测试会话中共享的config对象:

    def pytest_configure(config):
    config.foo = 'bar'
    @pytest.fixture
    def somefixture(pytestconfig):
    assert pytestconfig.foo == 'bar'
    def test_foo(pytestconfig):
    assert pytestconfig.foo == 'bar'
    

    在夹具/测试之外,您可以通过pytest.config访问配置,例如:

    @pytest.mark.skipif(pytest.config.foo == 'bar', reason='foo is bar')
    def test_baz():
    ...
    
  3. 使用缓存;这具有在测试运行之间持久化数据的附加功能:

    def pytest_configure(config):
    config.cache.set('foo', 'bar')
    @pytest.fixture
    def somefixture(pytestconfig):
    assert pytestconfig.cache.get('foo', None)
    def test_foo(pytestconfig):
    assert pytestconfig.cache.get('foo', None)
    @pytest.mark.skipif(pytest.config.cache.get('foo', None) == 'bar', reason='foo is bar')
    def test_baz():
    assert True
    

使用 1. 或 2. 时,请确保不会无意中用自己的数据覆盖pytest内容;最好在自己的变量前面加上唯一的名称。使用缓存时,您没有这个问题。

最新更新