跳过主要内容

pytest插件,用于中止挂起的测试

项目描述

python version anaconda ci pre-commit

此插件将计时每个测试,并在它耗时太长时终止它。终止可能或可能不会是优雅的,请参见下文,但终止时将显示当时所有线程的堆栈转储。这在运行测试于持续集成服务器或如果你不知道测试套件为什么挂起时很有用。

pytest-timeout插件已在Python 3.6及更高版本上进行了测试,包括PyPy3。请参阅tox.ini以查看当前测试的版本。

使用方法

安装非常简单,例如:

pip install pytest-timeout

现在你可以设置一个超时时间(以秒为单位)来运行测试套件,任何超过给定持续时间的单个测试都将被终止

pytest --timeout=300

此外,你还可以使用装饰器为单个测试设置超时。如果与--timeout标志结合使用,则将覆盖此单个测试的超时

@pytest.mark.timeout(60)
def test_foo():
    pass

默认情况下,插件不会超时任何测试,你必须指定一个有效的超时,插件才能中断长时间运行的测试。超时始终指定为秒数,可以以多种方式定义,从低到高优先级

  1. 你可以在pytest配置文件中使用timeout选项设置全局超时。例如:

    [pytest]
    timeout = 300
  2. PYTEST_TIMEOUT环境变量设置全局超时,覆盖配置文件中可能存在的值。

  3. --timeout命令行选项设置全局超时,覆盖环境变量和配置选项。

  4. 使用测试项目的timeout 标记,你可以为每个测试项目指定超时。

    @pytest.mark.timeout(300)
    def test_foo():
        pass

将超时设置为0秒将禁用超时,因此如果你已设置了全局超时,你可以使用标记来禁用超时。

超时方法

中断挂起的测试并不总是那么简单,并且可能取决于平台。此外,某些终止测试的方法可能与被测试的代码本身冲突。pytest-timeout插件会尝试根据你的平台选择最合适的方法,但偶尔你可能需要明确指定特定的超时方法。

如果超时方法不起作用,你最好的选择是使用thread方法。

thread

这是最可靠且最通用的方法。它也是在不支持signal方法的情况下默认使用的方法。对于每个测试项目,pytest-timeout插件启动一个计时器线程,该线程将在指定超时后终止整个进程。当测试项目完成时,计时器线程被取消,测试继续运行。

这种方法的缺点是每次运行测试都有相对较大的开销,并且测试运行并未完成。这意味着其他pytest特性,例如JUnit XML输出或fixture清理,将无法正常工作。第二个问题可以通过使用pytest-xdist插件的--boxed选项来缓解。

这种方法的优点是它始终有效。此外,它还会通过将应用程序中所有线程的堆栈打印到stderr来提供调试信息。

信号

如果系统支持SIGALRM信号,则默认使用signal方法。该方法在测试项开始时安排闹钟,在测试完成后取消闹钟。如果在测试过程中闹钟到期,信号处理程序将任何其他正在运行的线程的堆栈转储到stderr,并使用pytest.fail()来中断测试。

这种方法的优点是pytest进程不会被终止,测试运行可以正常完成。

使用此方法的主要问题在于它可能会干扰待测试的代码。如果待测试的代码本身使用SIGALRM,则事情会出错,您将不得不选择thread方法。

指定超时方法

可以通过在pytest配置文件中使用timeout_method选项、使用--timeout_method命令行参数或使用timeout 标记来指定超时方法。只需将这些值的字符串设置为threadsignal,以覆盖默认方法。在标记中,这是通过使用method关键字完成的

@pytest.mark.timeout(method="thread")
def test_foo():
    pass

timeout标记API

timeout标记的完整签名是

pytest.mark.timeout(timeout=0, method=DEFAULT_METHOD)

您可以为超时和方法使用位置参数或关键字参数。它们都不需要存在。

请参阅标记API的文档示例,了解标记可以应用于测试项的各种方式。

在Fixture清理中的超时

插件会在fixture的finaliser中愉快地终止超时。指定的超时适用于设置 fixtures、运行测试和清理 fixtures 的整个过程。然而,当在 fixture finaliser 中发生超时并且测试套件继续运行时,即使用信号方法,必须意识到可能尚未执行需要被清理的后续 fixtures,这可能会导致测试套件损坏。在这种情况下,可能会产生更清晰的输出的线程方法可能是一个更好的选择。

避免在Fixtures中的超时

超时适用于整个测试,包括可能需要为测试设置或清理的任何 fixtures(受影响的 fixtures 的确切情况取决于它们的范围以及是否有其他测试将使用相同的 fixture)。如果超时确实太短而无法包括 fixture 的持续时间,首先增加超时时间;()。如果这真的不是一个选择,pytest ini配置文件中存在一个名为timeout_func_only的布尔设置,如pytest --help中所述。

对于装饰函数,装饰器会覆盖pytest ini文件中的timeout_func_only = true到默认值。如果您需要保留装饰测试的此选项,必须再次明确指定该选项。

@pytest.mark.timeout(60, func_only=True)
def test_foo():
    pass

调试器检测

此插件试图在检测到调试器时避免触发超时。这主要是为了方便,这样您就不必记得在交互式调试时禁用超时。

此插件通过检查是否设置了跟踪函数来检测调试会话是否处于活动状态。如果设置了跟踪函数,则检查它所属的模块是否存在于已知调试框架模块的集合中,或者pytest自身是否使用--pdb或类似选项将您放入pdb会话。

可以通过使用--disable-debugger-detection标志或相应的timeout_disable_debugger_detection ini设置/环境变量来禁用此功能。

扩展pytest-timeout插件

pytest-timeout提供了两个钩子,可用于扩展工具。这些钩子用于设置超时定时器,并在超时未到达时取消它。

例如,pytest-asyncio可以提供针对asyncio的特定代码,生成更好的跟踪回溯,并在超时的await上提供提示,而不是在运行循环迭代上。

有关使用自定义钩子的更多信息,请参阅pytest钩子文档

pytest_timeout_set_timer

@pytest.hookspec(firstresult=True)
def pytest_timeout_set_timer(item, settings):
    """Called at timeout setup.

    'item' is a pytest node to setup timeout for.

    'settings' is Settings namedtuple (described below).

    Can be overridden by plugins for alternative timeout implementation strategies.
    """

设置

当调用pytest_timeout_set_timer时,将传递settings参数。

该参数具有Settings命名元组类型,具有以下字段

属性

索引

timeout

0

以秒为单位的超时或None表示没有超时

method

1

方法机制,默认支持'signal''thread'

func_only

2

如果True,则仅对测试函数应用超时

否则包装所有测试函数及其固定装置

pytest_timeout_cancel_timer

@pytest.hookspec(firstresult=True)
def pytest_timeout_cancel_timer(item):
    """Called at timeout teardown.

    'item' is a pytest node which was used for timeout setup.

    Can be overridden by plugins for alternative timeout implementation strategies.
    """

is_debugging

当发生超时时,用户可以打开调试会话。在这种情况下,应该丢弃超时。自定义钩子可以通过调用is_debugging()函数来检查此情况

import pytest
import pytest_timeout


def on_timeout():
    if pytest_timeout.is_debugging():
        return
    pytest.fail("+++ Timeout +++")

会话超时

上述提到的超时都是针对每个测试函数的。针对每个测试函数的超时将停止单个测试函数运行时间过长。我们可能还希望限制在一个会话中运行的整个测试集的时间。会话是指在一次pytest调用中运行的测试。

会话超时使用–session-timeout设置,单位为秒。

以下示例显示了10分钟(600秒)的会话超时

pytest --session-timeout=600

您还可以使用pytest配置文件中的session_timeout选项设置会话超时

[pytest]
session_timeout = 600

协作超时

会话超时是协作超时。pytest-timeout在每个测试函数结束时检查会话时间,如果会话超时,则停止进一步运行测试。如果发生这种情况,会话将导致测试失败。

特别是这意味着如果测试本身没有完成,只有在设置了函数超时的情况下才会被中断。会话超时不足以保证测试套件一定完成。

结合会话和函数超时

结合会话和函数超时是可以正常工作的。实际上,当使用会话超时时,建议也提供函数超时。

例如,限制测试函数为5秒,整个会话为100秒

pytest --timeout=5 --session-timeout=100

变更日志

2.3.1

  • 修复一些构建错误,主要是README语法,这阻止了twine上传。

2.3.0

  • 修复了最近版本的 VSCode 的调试器检测问题,现在使用 Cython 编译 pydevd,可以正确检测。感谢 Adrian Gielniewski。

  • 改为使用 Pytest 的 TerminalReporter 而不是直接写入 sys.{stdout,stderr}。此更改还将所有输出从 sys.stderr 切换到 sys.stdout。感谢 Pedro Algarvio。

  • Pytest 7.0.0 现在是最小支持的版本。感谢 Pedro Algarvio。

  • 添加了 --session-timeout 选项和 session_timeout 设置。感谢 Brian Okken。

2.2.0

  • 添加了 --timeout-disable-debugger-detection 标志,感谢 Michael Peters。

2.1.0

  • 从 shutil 获取终端宽度,而不是过时的 py,感谢 Andrew Svetlov。

  • 添加了用于通过第三方插件扩展 pytest-timeout 功能的 API,感谢 Andrew Svetlov。

2.0.2

  • 修复了在 macOS 上的调试器检测问题,感谢 Alexander Pacha。

2.0.1

  • 修复了删除 Python 2 的问题,感谢 Nicusor Picatureanu。

2.0.0

  • 将 pytest 的要求提高到 >=5.0.0。感谢 Dominic Davis-Foster。

  • 当插件不是从主线程调用时,使用线程超时方法以避免崩溃。

  • 修复了 PyCharm 调试器检测问题,以避免在调试器使用期间触发超时。

  • 不再支持 Python 2,最低支持的 pytest 版本是 5.0.0。

1.4.2

  • 修复了与 pytest 预发布版本运行时的兼容性问题,感谢 Bruno Oliveira。

  • 修复了对第三方调试器的检测问题,感谢 Bruno Oliveira。

1.4.1

  • 修复了由 1.4.0 版本破坏的覆盖率兼容性问题。

1.4.0

  • 改进了检测调试情况的准确性,感谢 Mattwmaster58。

1.3.4

  • 给线程命名以帮助调试,感谢 Thomas Grainger。

  • 由于 bitbucket 正在停止 mercurial 支持,已将位置更改为 https://github.com/pytest-dev/pytest-timeout。感谢 Thomas Grainger 和 Bruno Oliveira。

1.3.3

  • 修复了对 pytest >= 3.10 的支持。

1.3.2

  • 此变更日志在 1.3.2 版本发布时被省略,之后添加。为造成的混乱道歉。

  • 修复了 pytest 3.7.3 的兼容性问题。捕获 API 已有微小变化,需要修复。感谢 Bruno Oliveira 的贡献。

1.3.1

  • 修复了在 Python 3.6 上的弃用警告,感谢 Mickaël Schoentgen。

  • 创建了一个有效的标签以供发布。不知何故,对于 1.3.0 版本没有这样做,该标签指向一个不存在的提交。

1.3.0

  • 现在可以在测试函数上而不是在完整的 fixture 设置 + 测试 + 清理持续时间上运行超时计时器。感谢 Pedro Algarvio 的工作!

  • 使用新的 pytest 标记 API,感谢 Pedro Algarvio 的工作!

1.2.1

  • 修复了对 pytest 3.3 的支持,感谢 Bruno Oliveira。

  • 更新支持的 Python 版本:- 添加 CPython 3.6。- 删除 CPyhon 2.6(与 pytest 3.3 一样)- 删除 CPyhon 3.3 - 删除 CPyhon 3.4

1.2.0

  • 允许使用浮点数作为超时,而不是只使用整数,感谢 Tom Myers。

1.1.0

  • 在标题中报告(默认)超时持续时间,感谢 Holger Krekel。

1.0.0

  • 将版本提升到 1.0 以承诺语义版本化。

  • 修复问题 #12:现在与 pytest 2.8 兼容,感谢 Holger Krekel。

  • 不再使用 pexpect 在 py26 上进行测试,因为它不再受支持

  • 要求 pytest 2.8 并使用新的 hookimpl 装饰器

0.5

  • 当在由 pytest.set_trace() / pdb.set_trace() 启动的交互式 pdb 会话中时,不再触发超时。

  • 在 tox.ini 中添加了 pypy3 环境。

  • 将仓库转移到 pytest-dev 团队账户。

0.4

  • 支持在(会话范围)finalizers 中发生的超时。

  • 将命令行选项 –timeout_method 改为 –timeout-method,以与 pytest 保持一致

0.3

  • 添加了 PYTEST_TIMEOUT 环境变量,作为指定超时的方法(关闭问题 #2)。

  • 更灵活的标记参数解析:您现在可以使用位置参数指定方法。

  • 插件现在默认启用。无需再在配置文件或命令行中指定 timeout=0,仅为了让标记正常工作。

0.2

  • 使用 @pytest.timeout(N) 语法添加标记以修改超时延迟,感谢 Laurant Brack 提供的初始代码。

  • 允许超时标记通过使用 method 关键字参数来选择超时方法。

  • 将 –nosigalrm 选项重命名为 –method=thread,以支持未来对 eventlet 和 gevent 的支持。感谢 Ronny Pfannschmidt 提供的提示。

  • timeouttimeout_method 项目添加到配置文件,以便您可以使用 ini 文件启用和配置插件。感谢 Holger Krekel 和 Ronny Pfannschmidt 提供的提示。

  • 在 python 2.6、2.7 和 3.2 上进行了测试(并修复)。

项目详情


下载文件

下载您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分布

pytest-timeout-2.3.1.tar.gz (17.7 kB 查看哈希值)

上传时间

构建分布

pytest_timeout-2.3.1-py3-none-any.whl (14.1 kB 查看哈希值)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面