pytest-rerunfailures
.. START-SHORT-DESCRIPTION
pytest-rerunfailures 是一个 pytest <https://pytest.org>_ 插件,
用于重新运行测试以消除间歇性失败。
.. END-SHORT-DESCRIPTION
.. image:: https://img.shields.io/badge/license-MPL%202.0-blue.svg :target: https://github.com/pytest-dev/pytest-rerunfailures/blob/master/LICENSE :alt: License .. image:: https://img.shields.io/pypi/v/pytest-rerunfailures.svg :target: https://pypi.python.org/pypi/pytest-rerunfailures/ :alt: PyPI .. image:: https://github.com/pytest-dev/pytest-rerunfailures/workflows/Test/badge.svg :target: https://github.com/pytest-dev/pytest-rerunfailures/actions :alt: GitHub Actions .. image:: https://readthedocs.org/projects/pytest-rerunfailures/badge/?version=latest :target: https://pytest-rerunfailures.readthedocs.io/latest/?badge=latest :alt: Documentation Status
.. START-INSTALLATION
Requirements
要使用 pytest-rerunfailures,您需要满足以下先决条件:
- Python 3.10+ 或 PyPy3
- pytest 8.2 或更高版本
该插件可以在满足以下可选 先决条件的情况下从严重崩溃中恢复:
- pytest-xdist 2.3.0 或更高版本
当前该包针对最近 5 个次要版本的 pytest 进行了测试。如果 您使用的是旧版本的 pytest,应考虑更新或 使用该包的较早版本。
Installation
要安装 pytest-rerunfailures:
.. code-block:: bash
$ pip install pytest-rerunfailures
.. END-INSTALLATION
从严重崩溃中恢复
如果一个或多个测试触发了严重崩溃(例如:段错误),此插件通常将无法重新运行该测试。但是,如果安装了兼容版本的
pytest-xdist,并且测试在 pytest-xdist 中使用 -n
标志运行,则此插件将能够重新运行崩溃的测试,前提是 worker 和
controller 位于同一局域网(由于大多数情况下 worker 和 controller 位于同一台计算机上,因此这一假设在几乎所有情况下都成立)。
如果该假设不成立,则此功能可能无法正常工作。
重新运行所有失败
要重新运行所有测试失败,请使用 --reruns 命令行选项,并指定
您希望测试运行的最大次数:
.. code-block:: bash
$ pytest --reruns 5
失败的 fixture 或 setup_class 也将被重新执行。
要在重新运行之间添加延迟时间,请使用 --reruns-delay 命令行
选项,并指定在启动下一次
测试重新运行之前希望等待的秒数:
.. code-block:: bash
$ pytest --reruns 5 --reruns-delay 1
要在每次尝试后增加延迟(指数退避),请使用
--reruns-delay-backoff-factor 选项。第 n 次重新运行前的延迟为
reruns_delay * reruns_delay_backoff_factor ** (n - 1)。默认因子为
1.0,这将保持延迟恒定。例如,以下示例在三次重新运行前分别等待 1、2
和 4 秒:
.. code-block:: bash
$ pytest --reruns 3 --reruns-delay 1 --reruns-delay-backoff-factor 2
重新运行匹配特定表达式的所有失败
要仅重新运行匹配特定表达式列表的失败,请使用
--only-rerun 标志并传入一个正则表达式。例如,
以下命令将仅重新运行匹配 AssertionError 的错误:
.. code-block:: bash
$ pytest --reruns 5 --only-rerun AssertionError
多次传递该标志会累积参数,因此以下命令
将仅重新运行匹配 AssertionError or ValueError 的错误:
.. code-block:: bash
$ pytest --reruns 5 --only-rerun AssertionError --only-rerun ValueError
重新运行除匹配特定表达式外的所有失败
要仅重新运行不匹配特定表达式列表的失败,请使用
--rerun-except 标志并传入一个正则表达式。例如,
以下命令将仅重新运行不匹配 AssertionError 的错误:
.. code-block:: bash
$ pytest --reruns 5 --rerun-except AssertionError
多次传递该标志会累积参数,因此以下命令
将仅重新运行不匹配 AssertionError or OSError 的错误:
.. code-block:: bash
$ pytest --reruns 5 --rerun-except AssertionError --rerun-except OSError
重新运行单个失败
要将单个测试标记为不稳定(flaky),并在其失败时自动重新运行,请添加 flaky 标记,并指定你希望测试运行的最大次数:
.. code-block:: python
@pytest.mark.flaky(reruns=5) def test_example(): import random assert random.choice([True, False])
请注意,当 teardown 失败时,会为该用例生成两个报告,一个针对测试用例,另一个针对 teardown 错误。
你还可以在标记中指定重新运行的延迟时间,以及用于指数退避的退避因子:
.. code-block:: python
@pytest.mark.flaky(reruns=5, reruns_delay=2) def test_example(): import random assert random.choice([True, False])
.. code-block:: python
@pytest.mark.flaky(reruns=5, reruns_delay=2, reruns_delay_backoff_factor=2) def test_example(): import random assert random.choice([True, False])
你还可以在重新运行标记中指定一个可选的 condition:
.. code-block:: python
@pytest.mark.flaky(reruns=5, condition=sys.platform.startswith("win32")) def test_example(): import random assert random.choice([True, False])
可以通过分别为 only_rerun and rerun_except. They override the --only-rerun 和
--rerun-except 命令行参数指定正则表达式来实现异常过滤。
参数可以是单个字符串:
.. code-block:: python
@pytest.mark.flaky(rerun_except="AssertionError") def test_example(): raise AssertionError()
或者是一个字符串列表:
.. code-block:: python
@pytest.mark.flaky(only_rerun=["AssertionError", "ValueError"]) def test_example(): raise AssertionError()
异常类也被接受,并匹配任何子类:
.. code-block:: python
@pytest.mark.flaky(only_rerun=[AssertionError, ValueError]) def test_example(): raise AssertionError()
你可以使用 @pytest.mark.flaky(condition) similarly as @pytest.mark.skipif(condition), see pytest-mark-skipif <https://docs.pytest.org/en/6.2.x/reference.html#pytest-mark-skipif>_
.. code-block:: python
@pytest.mark.flaky(reruns=2,condition="sys.platform.startswith('win32')")
def test_example():
import random
assert random.choice([True, False])
# totally same as the above
@pytest.mark.flaky(reruns=2,condition=sys.platform.startswith("win32"))
def test_example():
import random
assert random.choice([True, False])
请注意,对于任何为真值的 condition,测试都将重新运行。
强制重新运行次数
要全局强制特定的重新运行次数,而不管测试标记中指定的重新运行次数,请传递 --force-reruns:
.. code-block:: bash
$ pytest --force-reruns 5
重新运行模式
默认情况下,标记中的计数严格优先于全局 --reruns
设置。若要使其变为累加,请传递 --reruns-mode=append。使用
append, a test decorated with @pytest.mark.flaky(reruns=2) 运行
--reruns 4 will be re-run up to `` 次:
.. code-block:: bash
$ pytest --reruns 4 --reruns-mode append
限制整个测试套件的总重新运行次数
为了限制整个测试套件中重跑的总次数,无论有多少个单独的测试失败,请传入 --max-suite-reruns。一旦达到该限制,即使单独的测试仍有剩余的重跑次数,也不会再进行任何重跑:
.. code-block:: bash
$ pytest --reruns 3 --max-suite-reruns 10
这在大型测试套件中非常有用,可以在许多测试同时不稳定时限制资源使用。该上限在重跑选择之后应用,包括配置了 --force-reruns and @pytest.mark.flaky 的测试。
显示重试失败的 traceback
默认情况下,只有不稳定测试的最终尝试会产生 traceback,因此来自早期尝试的失败(包括那些在重跑后最终通过的测试)会被静默丢弃。若要检查它们,请传入
--rerun-show-tracebacks:
.. code-block:: bash
$ pytest --reruns 2 --rerun-show-tracebacks
每次重试尝试的 traceback 都会追加到 rerun test summary info 部分。当设置该标志时,该部分会自动输出,
因此不需要 -rR。
输出
以下是插件在运行 --reruns 2 and -r aR 时提供的输出示例::
test_report.py RRF
================================== FAILURES ================================== __________________________________ test_fail _________________________________
def test_fail():
assert False
E assert False
test_report.py:9: AssertionError ============================ 重跑测试摘要信息 ========================= 重跑 test_report.py::test_fail 重跑 test_report.py::test_fail ============================ 简短测试摘要信息 ========================= 失败 test_report.py::test_fail ======================= 1 个失败, 2 次重跑, 耗时 0.02 秒 ====================
注意,输出将显示所有重跑。在所有重跑中均失败的测试 将被标记为失败。
.. START-COMPATIBILITY
兼容性
- 此插件与 pytest-xdist 的 --looponfail 标志不兼容。
- 此插件与核心 --pdb 标志不兼容。
- 此插件与插件
flaky <https://pypi.org/project/flaky/>_ 不兼容,你只能拥有pytest-rerunfailuresorflaky,而不能同时拥有两者。
.. END-COMPATIBILITY
.. START-PRIORITY
优先级
你可以在三个地方指定参数。因此,如果你在全部三个地方都设置了重跑次数, 哪一个具有优先级?
- 最高优先级是标记,例如
@pytest.mark.flaky(reruns=1) - 第二优先级是命令行上指定的内容,例如
--reruns=2 - 最低优先级是
pyproject.toml(orpytest.ini) file setting, likereruns = 3
此外,通过在命令行上传递 --force-reruns 参数,
可以覆盖上述三者。传递 --reruns-mode=append 会使标记计数和
全局 --reruns / reruns ini 设置变为累加而非严格模式。
.. END-PRIORITY
.. START-CONTRIBUTING
资源
Issue Tracker <https://github.com/pytest-dev/pytest-rerunfailures/issues>_Code <https://github.com/pytest-dev/pytest-rerunfailures/>_
Development
-
测试执行次数可从测试
item对象的execution_count属性中获取。示例:.. code-block:: python
@hookimpl(tryfirst=True) def pytest_runtest_makereport(item, call): print(item.execution_count)
.. END-CONTRIBUTING