如果多个测试有特定异常,则停止 pytest 测试
stop pytest tests if several tests have a specific exception
如果任何测试因特定异常而失败,我想使用 pytest.exit()
停止测试套件。
例如:
50 个测试,其中任何一个都可能在某个时候因该异常而失败,如果这些测试中至少有 2 个测试因该异常而失败,我想停止执行。
我试图在测试之间保留一个全局计数器(一个带有 scope='session'
的夹具)并在每次捕获此异常时更新它,但无法在测试之间保留它的值。
有什么想法吗?
这可以通过使用 Hooks 来实现。
具体来说,我们将利用两个特定的钩子,pytest_sessionstart
and pytest_exception_interact
。我们将使用 pytest_sessionstart
来跟踪我们愿意容忍的特定异常的数量,将其视为存储您提到的“全局计数器”的地方。另一个钩子 pytest_exception_interact
将用于与失败的测试交互以检查返回的异常类型(如果有)。
在测试文件夹的根目录中创建一个 conftest.py
文件并放置以下内容:
import pytest
EXC_MAP = {
ZeroDivisionError: 1,
KeyError: 1
}
def pytest_sessionstart(session):
session.__exc_limits = EXC_MAP
def pytest_exception_interact(node, call, report):
session = node.session
type_ = call.excinfo.type
if type_ in session.__exc_limits:
if session.__exc_limits[type_] == 0:
pytest.exit(f"Reached max exception for type: {type_}")
else:
session.__exc_limits[type_] -= 1
EXC_MAP
是我们愿意在测试调用中允许的异常映射 --> 失败。在 pytest_sessionstart
挂钩中,我们在 session
上设置了一个私有变量来跟踪这些变量。在 pytest_exception_interact
钩子中,我们得到测试引发的异常类型,我们根据阈值检查它,如果该异常的计数已达到 0,我们从 pytest
退出,跳过剩下的测试。
下面是一个示例测试脚本和终端中的输出。
def foo(a, b):
return a / b
def test_foo():
result = foo(1, 0)
assert result == 1
def test_foo1():
result = foo(1, 1)
assert result == 1
def test_foo2():
result = foo(1, 0)
assert result == 1
def test_foo3():
result = foo(1, 1)
assert result == 1
当 运行 这些终端显示时:
collected 4 items
test_foo.py F.F
========================================================================== FAILURES ==========================================================================
__________________________________________________________________________ test_foo __________________________________________________________________________
def test_foo():
> result = foo(1, 0)
test_foo.py:6:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 1, b = 0
def foo(a, b):
> return a / b
E ZeroDivisionError: division by zero
test_foo.py:2: ZeroDivisionError
_________________________________________________________________________ test_foo2 __________________________________________________________________________
def test_foo2():
> result = foo(1, 0)
test_foo.py:16:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 1, b = 0
def foo(a, b):
> return a / b
E ZeroDivisionError: division by zero
test_foo.py:2: ZeroDivisionError
================================================================== short test summary info ===================================================================
FAILED test_foo.py::test_foo - ZeroDivisionError: division by zero
FAILED test_foo.py::test_foo2 - ZeroDivisionError: division by zero
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! _pytest.outcomes.Exit: Reached max exception for type: <class 'ZeroDivisionError'> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================================ 2 failed, 1 passed in 0.20s =================================================================
我们可以看到它收集了所有 4 个测试,但只有 运行 3 个,因为在 运行 最终测试之前达到了 ZeroDivisionError
的阈值。
如果任何测试因特定异常而失败,我想使用 pytest.exit()
停止测试套件。
例如: 50 个测试,其中任何一个都可能在某个时候因该异常而失败,如果这些测试中至少有 2 个测试因该异常而失败,我想停止执行。
我试图在测试之间保留一个全局计数器(一个带有 scope='session'
的夹具)并在每次捕获此异常时更新它,但无法在测试之间保留它的值。
有什么想法吗?
这可以通过使用 Hooks 来实现。
具体来说,我们将利用两个特定的钩子,pytest_sessionstart
and pytest_exception_interact
。我们将使用 pytest_sessionstart
来跟踪我们愿意容忍的特定异常的数量,将其视为存储您提到的“全局计数器”的地方。另一个钩子 pytest_exception_interact
将用于与失败的测试交互以检查返回的异常类型(如果有)。
在测试文件夹的根目录中创建一个 conftest.py
文件并放置以下内容:
import pytest
EXC_MAP = {
ZeroDivisionError: 1,
KeyError: 1
}
def pytest_sessionstart(session):
session.__exc_limits = EXC_MAP
def pytest_exception_interact(node, call, report):
session = node.session
type_ = call.excinfo.type
if type_ in session.__exc_limits:
if session.__exc_limits[type_] == 0:
pytest.exit(f"Reached max exception for type: {type_}")
else:
session.__exc_limits[type_] -= 1
EXC_MAP
是我们愿意在测试调用中允许的异常映射 --> 失败。在 pytest_sessionstart
挂钩中,我们在 session
上设置了一个私有变量来跟踪这些变量。在 pytest_exception_interact
钩子中,我们得到测试引发的异常类型,我们根据阈值检查它,如果该异常的计数已达到 0,我们从 pytest
退出,跳过剩下的测试。
下面是一个示例测试脚本和终端中的输出。
def foo(a, b):
return a / b
def test_foo():
result = foo(1, 0)
assert result == 1
def test_foo1():
result = foo(1, 1)
assert result == 1
def test_foo2():
result = foo(1, 0)
assert result == 1
def test_foo3():
result = foo(1, 1)
assert result == 1
当 运行 这些终端显示时:
collected 4 items
test_foo.py F.F
========================================================================== FAILURES ==========================================================================
__________________________________________________________________________ test_foo __________________________________________________________________________
def test_foo():
> result = foo(1, 0)
test_foo.py:6:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 1, b = 0
def foo(a, b):
> return a / b
E ZeroDivisionError: division by zero
test_foo.py:2: ZeroDivisionError
_________________________________________________________________________ test_foo2 __________________________________________________________________________
def test_foo2():
> result = foo(1, 0)
test_foo.py:16:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 1, b = 0
def foo(a, b):
> return a / b
E ZeroDivisionError: division by zero
test_foo.py:2: ZeroDivisionError
================================================================== short test summary info ===================================================================
FAILED test_foo.py::test_foo - ZeroDivisionError: division by zero
FAILED test_foo.py::test_foo2 - ZeroDivisionError: division by zero
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! _pytest.outcomes.Exit: Reached max exception for type: <class 'ZeroDivisionError'> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================================ 2 failed, 1 passed in 0.20s =================================================================
我们可以看到它收集了所有 4 个测试,但只有 运行 3 个,因为在 运行 最终测试之前达到了 ZeroDivisionError
的阈值。