根据 py.test 中的参数跳过测试
Skip test depending on parameter in py.test
我有一个带有 session
范围的测试夹具,它是参数化的,例如
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture():
...
在我的目录中,我有使用 pytest.mark.usefixtures("myfixture")
的文件和一个包含测试的文件应该是 运行 仅适用于 myfixture
参数 "two"
和 py.test 否则应该跳过它。
有什么方法可以在 py.test 中实现这一点,或者我是否需要在 myfixture()
函数中的某些 class 中设置一个特殊变量?
自己找到解决方案,可以在conftest.py
中定义函数:
def pytest_namespace():
return {"param": None}
而在 fixture 函数中我们可以做:
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture():
pytest.param = request.param
# ...
所以我们可以将测试 class 包装成:
@pytest.mark.skipif("pytest.param == 'value'")
class TestSmth(object):
...
我在尝试解决类似用例时遇到了这个问题。我的解决方案,以防它帮助任何人避免几个小时。这是一种从测试中覆盖夹具参数化的简单方法:
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture():
...
@pytest.mark.parameterize('myfixture', ['two'], indirect=True)
def test1(myfixture):
...
def test2(myfixture):
...
感谢https://hackebrot.github.io/pytest-tricks/mark_parametrize_with_indirect/解释间接的用法!
最简洁的方法是使用 pytest_collection_modifyitems
挂钩在测试集合被 运行
之前修改它们
鉴于您的灯具描述:
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture(request):
...
为您的测试添加自定义标记:
@pytest.mark.restriction("two")
def test_smth(self, myfixture):
...
然后使用自定义取消选择逻辑修改您的测试集合:
def pytest_collection_modifyitems(items, config):
""" deselect test items which do not match the fixture restriction """
deselection_items = []
for item in items:
# There may be a better way than regex to get the parameter
passed_param = re.search(r'\[(.+?)\]', item.name).group(1)
restrictions = set([mark.args[0] for mark in item.iter_markers(name='restriction')])
if len(restrictions) > 0:
if passed_param not in restrictions:
deselection_items.append(item)
items[:] = [item for item in items if item not in deselection_items]
config.hook.pytest_deselected(items=deselection_items)
我最终编写了自己的装饰器,我认为它相当简单和干净:
import functools
def skip_targets(excluded_values):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
paramA = kwargs['paramA']
if paramA in excluded_values:
pytest.skip('Param A "{}" currently not supported'.format(paramA))
func(*args, **kwargs)
return wrapper
return decorator
要停用对 paramA
使用夹具的测试,您可以像这样排除值 X
:
@skip_targets(['X'])
def test_param(self, paramA):
pass
我有一个带有 session
范围的测试夹具,它是参数化的,例如
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture():
...
在我的目录中,我有使用 pytest.mark.usefixtures("myfixture")
的文件和一个包含测试的文件应该是 运行 仅适用于 myfixture
参数 "two"
和 py.test 否则应该跳过它。
有什么方法可以在 py.test 中实现这一点,或者我是否需要在 myfixture()
函数中的某些 class 中设置一个特殊变量?
自己找到解决方案,可以在conftest.py
中定义函数:
def pytest_namespace():
return {"param": None}
而在 fixture 函数中我们可以做:
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture():
pytest.param = request.param
# ...
所以我们可以将测试 class 包装成:
@pytest.mark.skipif("pytest.param == 'value'")
class TestSmth(object):
...
我在尝试解决类似用例时遇到了这个问题。我的解决方案,以防它帮助任何人避免几个小时。这是一种从测试中覆盖夹具参数化的简单方法:
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture():
...
@pytest.mark.parameterize('myfixture', ['two'], indirect=True)
def test1(myfixture):
...
def test2(myfixture):
...
感谢https://hackebrot.github.io/pytest-tricks/mark_parametrize_with_indirect/解释间接的用法!
最简洁的方法是使用 pytest_collection_modifyitems
挂钩在测试集合被 运行
鉴于您的灯具描述:
@pytest.fixture(scope="session", params=["one", "two", "three"])
def myfixture(request):
...
为您的测试添加自定义标记:
@pytest.mark.restriction("two")
def test_smth(self, myfixture):
...
然后使用自定义取消选择逻辑修改您的测试集合:
def pytest_collection_modifyitems(items, config):
""" deselect test items which do not match the fixture restriction """
deselection_items = []
for item in items:
# There may be a better way than regex to get the parameter
passed_param = re.search(r'\[(.+?)\]', item.name).group(1)
restrictions = set([mark.args[0] for mark in item.iter_markers(name='restriction')])
if len(restrictions) > 0:
if passed_param not in restrictions:
deselection_items.append(item)
items[:] = [item for item in items if item not in deselection_items]
config.hook.pytest_deselected(items=deselection_items)
我最终编写了自己的装饰器,我认为它相当简单和干净:
import functools
def skip_targets(excluded_values):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
paramA = kwargs['paramA']
if paramA in excluded_values:
pytest.skip('Param A "{}" currently not supported'.format(paramA))
func(*args, **kwargs)
return wrapper
return decorator
要停用对 paramA
使用夹具的测试,您可以像这样排除值 X
:
@skip_targets(['X'])
def test_param(self, paramA):
pass