pip install pytest-rerunfailures
示例代码
import pytest
from time import ctime
@pytest.mark.flaky(reruns=3, reruns_delay=2)
def test_a():
print(ctime())
import random
assert random.choice([True, False]) # 这个代码你可能直接passed了,随机的
if __name__ == '__main__':
pytest.main(['-sv',__file__])
示例输出
test_demo.py::test_a Sun Jan 29 09:39:35 2023
RERUN
test_demo.py::test_a Sun Jan 29 09:39:37 2023
PASSED
========================= 1 passed, 1 rerun in 2.13s ==========================
装饰器中的参数
结果会记录你rerun的次数
如果把assert改为
assert random.choice([1, 0, 0, 0, 0])
那你的输出很可能就是如下的
test_demo.py:10: AssertionError
=========================== short test summary info ===========================
FAILED test_demo.py::test_a - AssertionError: assert 0
========================= 1 failed, 3 rerun in 6.20s ==========================
flaky还有一个参数
示例代码
import sys
import pytest
from time import ctime
@pytest.mark.flaky(reruns=3, reruns_delay=2,condition=sys.platform.startswith('linux'))
def test_a():
print(ctime())
import random
assert random.choice([1, 0])
if __name__ == '__main__':
pytest.main(['-sv', __file__])
你测试多次会发现,遇到失败的情况压根就不会重跑的,因为condition不满足
跟多数插件一样,它也支持命令行的用法
你可以这样用
$ pytest --reruns 5 --reruns-delay 1
但是condition并没有这个命令行,它变成了--only-rerun(确切的说也不是变,有点不太一样了)
# 遇到AssertionError错误就重跑
$ pytest --reruns 5 --only-rerun AssertionError
# 遇到AssertionError或者ValueError 就重跑
$ pytest --reruns 5 --only-rerun AssertionError --only-rerun ValueError
示例代码
def test_a():
assert int('a') # 会产生一个ValueError
pytest -sv --reruns 2 --reruns-delay 1 --only-rerun ValueError test_demo.py
test_demo.py:4: ValueError
==================== short test summary info =================================================
FAILED test_demo.py::test_a - ValueError: invalid literal for int() with base 10: 'a'
==================== 1 failed, 2 rerun in 0.06s ===============================================
--only-rerun的意思很明确,只有遇到ValueError才重跑
同样的代码,换个参数--rerun-except,除了ValueError才会重跑,遇到ValueError并不重跑
pytest -sv --reruns 2 --reruns-delay 1 --rerun-except ValueError test_demo.py
test_demo.py:4: ValueError
======================== short test summary info =================================================
FAILED test_demo.py::test_a - ValueError: invalid literal for int() with base 10: 'a'
======================== 1 failed in 0.06s ====================================================
测试AssertionError的时候 貌似跟我预期的不太一样,可能是我眼花了。
如果命令行没有-v显示的是R标记
test_demo.py RRF # 重跑了2次后失败了 , 对应底部的1 failed, 2 rerun in 0.06s
命令行
# command line options
def pytest_addoption(parser):
group = parser.getgroup(
"rerunfailures", "re-run failing tests to eliminate flaky failures"
)
group._addoption(
"--only-rerun",
action="append",
dest="only_rerun",
type=str,
default=None,
help="If passed, only rerun errors matching the regex provided. "
"Pass this flag multiple times to accumulate a list of regexes "
"to match",
)
group._addoption(
"--reruns",
action="store",
dest="reruns",
type=int,
default=0,
help="number of times to re-run failed tests. defaults to 0.",
)
group._addoption(
"--reruns-delay",
action="store",
dest="reruns_delay",
type=float,
default=0,
help="add time (seconds) delay between reruns.",
)
装饰器参数
def get_reruns_count(item):
...
if "reruns" in rerun_marker.kwargs:
...
def get_reruns_delay(item):
...
if "reruns_delay" in rerun_marker.kwargs:
...
def get_reruns_condition(item):
...
if rerun_marker is not None and "condition" in rerun_marker.kwargs:
...