pytest-timeout插件的介绍和使用
简介:
pytest-timeout
是非常实用的 pytest 插件,它可以为你的测试设置 超时时间,防止测试卡死或运行太久。这对于自动化测试、CI/CD 流水线、并行测试(如 pytest-xdist
)中特别有用。
准备:
插件安装:
pip install pytest-timeout
运行方式:
1、为所有测试设置超时时间(单位:秒)
pytest --timeout=30 --timeout-method=thread
这表示:每个测试最多运行 30 秒,超过则报错。
aignal
:(默认):使用信号中断测试(在 Unix 系统上)。使用signal
方法在 Windows 上运行测试,当测试超时时,可能不会按预期终止测试,从而导致测试挂起或卡死。thread
:使用线程检测超时(跨平台,但不强制中断)。通过线程的方式来监控测试执行的时间,并在超时时中断测试,这种方法是跨平台兼容的,适用于所有操作系统,包括 Windows。
2、为单个测试设置超时时间
使用 @pytest.mark.timeout()
装饰器:
这个 @pytest.mark.timeout()
标记的优先级比 1、4步骤更高!
import pytest
import time
@pytest.mark.timeout(5) # 这个测试最多运行 5 秒
def test_slow_function():
time.sleep(6) # 会超时
3、禁用某个测试的超时机制
@pytest.mark.timeout(None)
def test_no_timeout():
time.sleep(100) # 不会超时
- Unix 系统(Linux/macOS)可以完美支持
signal
和thread
两种模式。
- Windows 只能使用
thread
模式,且对None
的处理存在缺陷。(可通过超大超时值替代 None)
4、在 pytest.ini 中设置默认超时时间
[pytest]
timeout = 5
timeout_method = thread # 推荐在 Windows 上使用 thread
所有测试用例默认超时时间为5秒!
示例:
pytest.ini 文件
[pytest]
# pytest-xdist 插件运行指令 -n auto
addopts = -v -n 2 --capture=no
# 禁用xdist
# addopts = -p no:xdist
# pytest-timeout 超时配置
timeout = 3
timeout_method = thread
*.py 文件
import pytest
import time
# 这个测试会超时(运行 5 秒 > 3 秒)
def test_too_slow():
print("Starting slow test...")
time.sleep(5)
assert True
# 这个测试正常(运行 1 秒 < 3 秒)
def test_fast():
print("Starting fast test...")
time.sleep(1)
assert True
# 这个测试被标记超时时间10秒,优先级高于ini文件,故用例不会超时
@pytest.mark.timeout(10)
def test_long_but_allowed():
print("Starting long test (10s allowed)...")
time.sleep(7)
assert True
# @pytest.mark.timeout(None) 禁用超时,但在windows系统中该方法存在问题可能不生效,仅在linux系统中能生效。
# windows 中建议改为比较大的数来巧妙的“禁用超时”。
@pytest.mark.timeout(600)
def test_no_timeout():
print("This test has no timeout...")
time.sleep(5)
assert True
运行结果:
如果不安装使用 pytest-xdist
插件,运行结果就截然不同了!Timeout !!!
test\python_timeout_demo\test_pytest_timeout.py +++++++++++++++ Timeout +++++++++++++++
问题🧠:
在 Windows 系统上使用 pytest-timeout
时确实会遇到比 Linux/macOS 更多的问题,主要原因并不是 pytest-timeout
本身设计不好,而是因为Windows 与 Linux 的线程/信号机制不同。
1、Windows 与 Linux 的线程/信号机制不同
①. timeout_method = signal
不支持 Windows ❌
signal
是 Unix 系统(Linux/macOS)中的中断机制,可以精确地中断主线程。- Windows 没有
signal
这个机制,所以pytest-timeout
在 Windows 上只能使用thread
方法。
②. timeout_method = thread
在 Windows 上存在局限性 ⚠️
- 这是 Windows 上唯一可用的超时中断方法。
- 它通过创建一个“监控线程”来中断主线程。
- 但 这个方法无法中断某些阻塞调用,比如:
time.sleep()
input()
socket.recv()
os.wait()
- 等等
这些调用在 Windows 上是“不可中断的系统调用”,即使你设置了超时,它也会继续执行,直到完成。
2、单进程模式下, time.sleep()
在 Windows 上无法被中断?
这是 Python 的 time.sleep()
在 Windows 上的实现机制决定的:
- 它是基于 Windows API 的
Sleep()
函数(来自kernel32.dll
)。 - 这个函数是 阻塞式调用,不支持中断。
- 即使你从另一个线程尝试中断它,它也会“无视中断”继续休眠,直到时间结束。
✅ 如果使用了 pytest-xdist
插件多进程运行,就比较巧妙的规避了该问题。
3、Linux/macOS 上为何表现更好?
- 在 Linux/macOS 上,
time.sleep()
底层调用的是nanosleep()
或usleep()
,它们可以被信号中断。 pytest-timeout
使用signal
方法发送一个SIGALRM
信号,就能打断这些调用。- 所以在 Linux 上,
pytest-timeout
的行为更“智能”和“可控”。
评论区