如何处理测试失败

How to handle test failures

第一次(或 N 次)失败后停止

Stopping after the first (or N) failures

在前 (N) 次失败后停止测试过程:

pytest -x           # stop after first failure
pytest --maxfail=2  # stop after two failures

pdb — The Python Debugger 一起使用 pytest

Using pdb — The Python Debugger with pytest

在失败时转到 pdb

Dropping to pdb on failures

Python 自带了一个内置的调试器 pdbpytest 允许通过命令行选项进入 pdb 提示符:

pytest --pdb

这将在每次失败(或 KeyboardInterrupt)时调用 Python 调试器。 通常你可能只想在第一个失败的测试中进行调试,以便理解某个失败的情况:

pytest -x --pdb   # 第一个失败时进入 PDB,然后结束测试会话
pytest --pdb --maxfail=3  # 前三个失败进入 PDB

请注意,任何失败时的异常信息都会存储在 sys.last_valuesys.last_typesys.last_traceback 中。在交互式使用中,这允许使用任意调试工具进行事后调试。也可以手动访问异常信息,例如:

>>> import sys
>>> sys.last_traceback.tb_lineno
42
>>> sys.last_value
AssertionError('assert result == "ok"',)

在一个测试开始时转到 pdb

Dropping to pdb at the start of a test

pytest 允许人们在每个测试开始时通过命令行选项立即进入 pdb 提示符:

pytest --trace

这将在每个测试开始时调用 Python 调试器。

设置断点

Setting breakpoints

在代码中设置断点,可以使用原生 Python 调用 import pdb; pdb.set_trace()。pytest 会自动禁用该测试的输出捕获:

  • 其他测试的输出捕获不受影响。

  • 任何已捕获的先前测试输出将按原样处理。

  • 在结束调试会话(通过 continue 命令)时,输出捕获会恢复。

使用内置断点函数

Using the builtin breakpoint function

Python 3.7 引入了一个内置的 breakpoint() 函数。pytest 支持 breakpoint() 的使用,具有以下行为:

  • 当调用 breakpoint()PYTHONBREAKPOINT 设置为默认值时,pytest 将使用自定义的内部 PDB 调试界面,而不是系统默认的 Pdb

  • 测试完成后,系统将恢复使用系统默认的 Pdb 调试界面。

  • 通过 --pdb 参数传递给 pytest 时,自定义内部 Pdb 调试界面将用于 breakpoint() 调用、测试失败或未处理的异常。

  • 可以使用 --pdbcls 指定一个自定义的调试类。

故障处理

Fault Handler

Added in version 5.0.

标准模块 faulthandler 可用于在发生段错误或超时后导出 Python 堆栈跟踪。

除非在命令行中指定了 -p no:faulthandler,否则该模块会自动为 pytest 运行启用。

此外,faulthandler_timeout=X 配置选项可以用于在测试花费时间超过 X 秒后导出所有线程的堆栈跟踪(在 Windows 上不可用)。

Note

此功能已集成自外部 pytest-faulthandler 插件,但有以下两点小差异:

  • 禁用它时,使用 -p no:faulthandler 而不是 --no-faulthandler:前者适用于所有插件,从而节省了一个选项。

  • --faulthandler-timeout 命令行选项已成为 faulthandler_timeout 配置选项。仍然可以通过命令行使用 -o faulthandler_timeout=X 进行配置。

关于无法引发的异常和未处理的线程异常的警告

Warning about unraisable exceptions and unhandled thread exceptions

Added in version 6.2.

未处理的异常指在无法传递给调用者的情况下引发的异常。最常见的情况是在 __del__ 实现中引发的异常。

未处理的线程异常是在 Thread 中引发且未处理的异常,导致线程异常终止。

这两类异常通常被视为程序错误, 但可能因未导致程序崩溃而未被注意到。Pytest 可以检测这些情况,并在测试运行摘要中显示警告。

这些插件在 pytest 运行中自动启用,除非在命令行中指定 -p no:unraisableexception (用于未引发的异常)或 -p no:threadexception (用于线程异常)。

可以使用 pytest.mark.filterwarnings 标记有选择地关闭这些警告。警告类别为 pytest.PytestUnraisableExceptionWarningpytest.PytestUnhandledThreadExceptionWarning