是否有办法跳过pytest如果夹具设置或拆卸失败?



如果fixture的任何部分抛出异常,是否有跳过测试的方法?我使用的是第三方fixture,它在拆卸过程中往往会随机出错,所以我试图包装我的测试,以便如果抛出随机错误(注意:测试不是失败,是fixture出错),pytest只是跳过测试。

下面是一个最小的可复制示例:

import functools
import numpy as np
import pytest

def handle_fixture_errors(f):
"""decorator for wrapping test function in try/catch"""
@functools.wraps(f)
def wrapper(*args, **kwargs):
try:
print('about to run my test')
return f(*args, **kwargs)
print('never reached')
except Exception as e:
msg = 'Ignoring fixture exception ' + str(e)
pytest.skip(msg)
return wrapper
@pytest.fixture()
def failing_fixture(request):
"""fixture fails on teardown"""
x = np.linspace(10, 20, 100)
y = np.random.normal(size=(1000, 5))
def teardown():
print('fixture teardown is failing')
z = x.T.dot(y)
request.addfinalizer(teardown)
return x

@handle_fixture_errors
def test_matmul(failing_fixture):
"""original test function"""
print('hey this is my test')
k = failing_fixture
assert len(k) == 100

问题是测试本身没有抛出异常,是夹具抛出异常,所以try/catch没有捕获测试的异常并防止";从结果的测试总结。我的测试输出仍然是这样的:

========================================================= ERRORS =========================================================
____________________________________________ ERROR at teardown of test_matmul ____________________________________________
def teardown():
print('fixture teardown is failing')
>       z = x.T.dot(y)
E       ValueError: shapes (100,) and (1000,5) not aligned: 100 (dim 0) != 1000 (dim 0)
test_fake.py:25: ValueError
-------------------------------------------------- Captured stdout call --------------------------------------------------
about to run my test
hey this is my test
------------------------------------------------ Captured stdout teardown ------------------------------------------------
fixture teardown is failing
================================================ short test summary info =================================================
ERROR test_fake.py::test_matmul - ValueError: shapes (100,) and (1000,5) not aligned: 100 (dim 0) != 1000 (dim 0)
=============================================== 1 passed, 1 error in 0.18s ===============================================

我不想跳过设置或拆除夹具,我只想让测试被认为是"跳过"。完全(或至少,沉默或pass编辑)。谢谢你的帮助!

我认为跳过这样的测试是不合理的;你要么想要,要么不想要!

如果您有间歇性的测试(或者本例中的固定装置),请考虑重新运行它们,可能在短暂延迟或某些检查(网络流量过高?非高峰时间再试一次

pytest建议了一些插件,这些插件看起来质量很高,并且可以在运行之间添加延迟等
https://docs.pytest.org/en/stable/flaky.html#plugins

如果您确切地知道它将在哪里失败,请考虑在您的代码放弃或将控制权交还给pytest之前自己重新尝试几次,通过在某些循环中设计您的逻辑

for _ in range(10):  # attempt call 10 times
time.sleep(10)  # yuck
try:
foo = flakey_call()
except Exception:
continue  # failed: try again, consider different waits
if hasattr(foo, "bar"):
break  # successfully got a valid foo
else:  # did not find and break
raise Exception("the foo had no bar!")

也可以有选择地模拟第三方fixture(我要小心不要这样做,因为它可能导致fixture永远无法工作),或者每次运行

设计一些逻辑来获得第三方逻辑的响应,可能会在固定的情况下重新运行它,直到它做你想要的。

然后

  • 将其序列化为一些有用的形式,并保存它以供将来运行(例如parquet,如果它是一些数据收集)
  • pickle对象(我只会在有许多调用的单次运行中这样做,但现在只需要成功)

最新更新