pytest超时 - 失败测试,而不是杀死整个测试运行
我知道在pytest-timeout
我可以为每个测试用例指定tiemout,但单个失败终止整个测试运行,而不是失去松弛测试用例。pytest超时 - 失败测试,而不是杀死整个测试运行
我*做出自己的解决方案,或有准备好使用的工具,提供?
我很久以前就研究过这个问题,并得出了自制解决方案会更好的结论。
我的插件正在杀死整个pytest过程,但它可以被调整为只能通过一次(当前)测试。这里是调整草案:
import pytest
import signal
class Termination(SystemExit):
pass
class TimeoutExit(BaseException):
pass
def _terminate(signum, frame):
raise Termination("Runner is terminated from outside.")
def _timeout(signum, frame):
raise TimeoutExit("Runner timeout is reached, runner is terminating.")
@pytest.hookimpl
def pytest_addoption(parser):
parser.addoption(
'--timeout', action='store', dest='timeout', type=int, default=None,
help="number of seconds before each test failure")
@pytest.hookimpl
def pytest_configure(config):
# Install the signal handlers that we want to process.
signal.signal(signal.SIGTERM, _terminate)
signal.signal(signal.SIGALRM, _timeout)
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item, nextitem):
# Set the per-test timeout (an alarm signal).
if item.config.option.timeout is not None:
signal.alarm(item.config.option.timeout)
try:
# Run the setup, test body, and teardown stages.
yield
finally:
# Disable the alarm when the test passes or fails.
# I.e. when we get into the framework's body.
signal.alarm(0)
当你这样做kill -ALRM $pid
,或在每个测试超时单独由于预置报警,只有当前测试将失败,但其他的测试将继续进行。
而且这个TimeoutExit
将不会被except Exception: pass
的库所抑制,因为它从BaseException
继承。
所以在这方面与SystemExit
相同。但是,与SystemExit
或KeyboardInterruption
不同,pytest不会捕获它,并且不会退出这样的异常。
即使在time.sleep(...)
(对于任何信号)的情况下,异常都会被注入到测试所发生的任何地方。
请记住,您只能为过程设置一个警报(操作系统限制)。这也使其与pytest-timeout
不兼容,因为它也将ALRM信号用于相同的目的。
如果您希望全局测试超时时间为&,则必须实现智能报警管理器,该管理器将跟踪少量报警,将操作系统报警设置为最早的报警,并决定在何时调用哪个处理程序接收到报警信号。
在情况下,当你做kill -TERM $pid
或只是kill $pid
(正常终止)时,它会立即终止 - 因为它是从SystemExit
,这是BaseException
,通常不是由代码或pytest抓住继承。
后一种情况主要演示如何对不同的信号设置不同的反应。您可以使用USR1 & USR2和其他可捕捉信号做类似的事情。
对于快速测试,把上述至conftest.py
文件(伪插件)的插件代码。
考虑这个测试文件:
import time
def test_this():
try:
time.sleep(10)
except Exception:
pass
def test_that():
pass
不超时运行pytest什么都不做,都测试通过:
$ pytest -s -v
.........
collected 2 items
test_me.py::test_this PASSED
test_me.py::test_that PASSED
======= 2 passed in 10.02 seconds =======
与超时运行它失败的第一次测试,但通过第二一个:
$ pytest -s -v --timeout=5
.........
collected 2 items
test_me.py::test_this FAILED
test_me.py::test_that PASSED
============== FAILURES ==============
______________ test_this _____________
def test_this():
try:
> time.sleep(10)
test_me.py:5:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
signum = 14, frame = <frame object at 0x106b3c428>
def _timeout(signum, frame):
> raise TimeoutExit("Runner timeout is reached, runner is terminating.")
E conftest.pytest_configure.<locals>.TimeoutExit: Runner timeout is reached, runner is terminating.
conftest.py:24: TimeoutExit
======= 1 failed, 1 passed in 5.11 seconds =======
如果我有时间我不认为我会深入实施的细节深入挖掘,但这个我真的很有启发!我会保留这些作为参考。 – JCode