【问题标题】:Is there a way to skip pytest if fixture setup or teardown fails?如果夹具设置或拆卸失败,有没有办法跳过 pytest?
【发布时间】:2021-01-20 19:49:33
【问题描述】:

如果夹具的任何部分抛出异常,有没有办法跳过测试?我正在使用第三方夹具,该夹具在拆卸过程中会随机出错,因此我试图包装我的测试,以便在抛出随机错误时(注意:测试没有失败,夹具出错了) , 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 没有捕获测试的异常并阻止“.E”生成测试摘要。我的测试输出仍然是这样的:

========================================================= 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 ===============================================

我不想跳过设置或拆除夹具,我只想让测试被完全“跳过”(或者至少,静音或passed)。谢谢帮忙!

【问题讨论】:

  • 注释掉就行了
  • ...不,我需要夹具来运行其他测试。 failing_fixture 仅代表大多数 时间工作但随机失败的第三方固定装置,但在现实生活中它隐藏在另一个代码库中。需要能够在夹具确实失败时跳过测试,但在夹具工作时仍然使用它。

标签: python pytest fixtures


【解决方案1】:

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

如果您有 间歇性 测试(或者在这种情况下是固定装置),请考虑重新运行它们,也许在短暂的延迟或一些检查之后(网络流量太高?在非高峰期再试一次小时)

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!")

也可以选择模拟第 3 方夹具(我会提醒您不要这样做,因为它可能导致夹具永远无法工作),或者每次运行

设计一些逻辑来获得第 3 方逻辑的响应,可能会在夹具中重新运行它,直到它执行您想要的操作为止..

然后

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    • 2021-01-08
    • 2019-03-22
    • 1970-01-01
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多