从文档来看,编写跳过装饰器(您可以从例如
conftest.py
导入)的预期方法似乎是使用skipif
(https://docs.pytest.org/en/6.2.x) /skipping.html#id1)。但是,示例中显示的条件很简单,不需要与任何其他参数化交互。当您还需要检查参数作为要跳过的条件的一部分时,是否可以让 skipif
工作?
在https://github.com/scipy/scipy/blob/4a6db1500dc62870865fe7827524abd332a88fd9/scipy/conftest.py#L147-L180中,我们有装饰器可以正确执行我们想要的跳过,但是,(IIUC)因为我们使用
skip
而不是 skipif
,当我们使用 -rsx
时,跳跃被报告为来自 conftest.py
,例如SKIPPED [27] scipy/conftest.py:159: is_isomorphic only supports NumPy backend
。有没有一种方法可以编写装饰器,以便从它们起源的测试中报告跳过?
我们可以从
--verbose
恢复该信息,但如果这与 -rsx
一起使用会容易得多。干杯!
# conftest.py
array_api_compatible = pytest.mark.parametrize("xp", xp_available_backends.values())
def skip_if_array_api_gpu(func):
reason = "do not run with Array API on and not on CPU"
# method gets there as a function so we cannot use inspect.ismethod
if '.' in func.__qualname__:
@wraps(func)
def wrapped(self, *args, **kwargs):
xp = kwargs["xp"]
if SCIPY_ARRAY_API and SCIPY_DEVICE != 'cpu':
if xp.__name__ == 'cupy':
pytest.skip(reason=reason)
elif xp.__name__ == 'torch':
if 'cpu' not in torch.empty(0).device.type:
pytest.skip(reason=reason)
return func(self, *args, **kwargs)
else:
@wraps(func)
def wrapped(*args, **kwargs):
# ditto
return func(*args, **kwargs)
return wrapped
# example test
@skip_if_array_api_gpu
@array_api_compatible
def test_xxx(xp):
...
x-ref https://github.com/pytest-dev/pytest/discussions/11726
这是一个示例测试,显示
skipif
仅由于全局条件而跳过,但您可以生成自己的跳过包装器,该包装器会检测某些条件并继续进行测试,或者引发 skip()
报告测试已跳过。
import pytest
from pytest import skip
import functools
global_int = 2
def skipIfNotDynamic(test_method):
@functools.wraps(test_method)
def wrapper(self, **kwargs):
xp = kwargs["xp"]
if not xp:
raise skip(f"Skip because xp is Falsey during {test_method.__name__}")
return test_method(self, **kwargs)
return wrapper
array_api_compatible = pytest.mark.parametrize('xp', [1, 2, 0, 3])
class TestGroup:
@pytest.mark.skipif(global_int == 2, reason='global control')
def test_something(self):
assert True == False # add assertion here
@skipIfNotDynamic
@array_api_compatible
def test_else(self, xp):
assert xp == 0, "test_else"
输出:
F:\...>pytest -rsx soFunctionsEmulatingSkipif.py
================================================= test session starts =================================================
platform win32 -- Python 3.11.5, pytest-7.4.3, pluggy-1.3.0
rootdir: F:\...
collected 5 items
soFunctionsEmulatingSkipif.py sFFsF [100%]
====================================================== FAILURES =======================================================
_______________________________________________ TestGroup.test_else[1] ________________________________________________
self = <soFunctionsEmulatingSkipif.TestGroup object at 0x0000020F489545D0>, xp = 1
@skipIfNotDynamic
@array_api_compatible
def test_else(self, xp):
> assert xp == 0, "test_else"
E AssertionError: test_else
E assert 1 == 0
soFunctionsEmulatingSkipif.py:32: AssertionError
_______________________________________________ TestGroup.test_else[2] ________________________________________________
self = <soFunctionsEmulatingSkipif.TestGroup object at 0x0000020F48954B10>, xp = 2
@skipIfNotDynamic
@array_api_compatible
def test_else(self, xp):
> assert xp == 0, "test_else"
E AssertionError: test_else
E assert 2 == 0
soFunctionsEmulatingSkipif.py:32: AssertionError
_______________________________________________ TestGroup.test_else[3] ________________________________________________
self = <soFunctionsEmulatingSkipif.TestGroup object at 0x0000020F48920E90>, xp = 3
@skipIfNotDynamic
@array_api_compatible
def test_else(self, xp):
> assert xp == 0, "test_else"
E AssertionError: test_else
E assert 3 == 0
soFunctionsEmulatingSkipif.py:32: AssertionError
=============================================== short test summary info ===============================================
SKIPPED [1] soFunctionsEmulatingSkipif.py:25: global control
SKIPPED [1] soFunctionsEmulatingSkipif.py:14: Skip because xp is Falsey during test_else
============================================ 3 failed, 2 skipped in 0.80s =============================================
请参阅 https://github.com/pytest-dev/pytest/issues/11742#issuecomment-1937678284 了解我们的解决方案。我们最终使用了标记和固定装置。