常用插件
- pip install pytest-rerunfailures 失败重跑
- pip install pytest-assume 多重校验
- pip install pytest-ordering 控制用例的执行顺序
- pip install pytest-repeat 重复执行用例
pytest-rerunfailures
- 场景
- 测试失败后要重新运行n次,要在重新运行之间添加延迟时间、间隔n秒再运行。
- 安装
- pip install pytest-rerunfailures
- pip3 install pytest-rerunfailures -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
- 运行要求
- Python 3.6~3.9, or PyPy3
- pytest 5.0+
- 使用方式
- 命令行参数:--reruns n(重新运行次数),--reruns-delay m(等待运行秒数)
- 装饰器参数:reruns=n(重新运行次数),reruns_delay=m(等待运行秒数)
重新运行所有失败的用例
要重新运行所有测试失败,使用 --reruns 命令行选项,并指定要运行测试的最大次数:
pytest -vs --reruns 3 test_rerun.py
from time import sleep
def test_rerun1():
sleep(0.5)
assert 1 == 2
def test_rerun2():
sleep(0.5)
assert 2 == 2
def test_rerun2():
sleep(0.5)
assert 'h' == 'world'
执行结果:
test_rerun.py::test_rerun1 RERUN
test_rerun.py::test_rerun1 RERUN
test_rerun.py::test_rerun1 RERUN
test_rerun.py::test_rerun1 FAILED
test_rerun.py::test_rerun2 RERUN
test_rerun.py::test_rerun2 RERUN
test_rerun.py::test_rerun2 RERUN
test_rerun.py::test_rerun2 FAILED
添加重新运行的延时
要在两次重试之间增加延迟时间,使用 --reruns-delay 命令行选项,指定下次测试重新开始之前等待的秒数
pytest test_rerun.py --reruns 3 --reruns-delay 1
说明:明显看到重跑的两个测试用例之间有一段时间间隔
重新运行指定的测试用例
@pytest.mark.flaky(reruns=2,reruns_delay=2)
运行结果:
test_rerun.py::test_rerun1 FAILED
test_rerun.py::test_rerun2 PASSED
test_rerun.py::test_rerun3 RERUN
test_rerun.py::test_rerun3 RERUN
test_rerun.py::test_rerun3 FAILED
兼容性问题
- 不可以和fixture装饰器一起使用: @pytest.fixture()
- 该插件与pytest-xdist的 --looponfail 标志不兼容
- 该插件与核心--pdb标志不兼容
最后总结,这个插件虽然还用,但是坑还是不少,建议主要使用失败重试次数和重试间隔的功能即可。
pytest-assume
- 场景
- 一个方法中些多条断言,中间有一条失败,后面的代码就不执行了,我们希望有失败也能执行完毕。
- 安装
- pip install pytest-assume
- pip3 install pytest-assume -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
- 使用方式
- pytest.assume(1==4)
- pytest.assume(2==4)
assert 多重断言
def test_assume():
assert 1 == 2
assert False == True
assert 100 == 200
运行结果:
FAILED
test_assume.py:8 (test_assume)
1 != 2
Expected :2
Actual :1
<Click to see difference>
def test_assume():
> assert 1 == 2
E assert 1 == 2
test_assume.py:10: AssertionError
结论
可以看到,第一行断言失败之后,后面的断言也不会执行,包括正常的代码
pytest.assume多重断言
def test_assume():
# assert 1 == 2
# assert False == True
# assert 100 == 200
pytest.assume(1 == 1)
pytest.assume(False == True)
pytest.assume(100 == 200)
pytest.assume(4 != 1)
运行结果:
FAILED
test_assume.py:10 (test_assume)
tp = <class 'pytest_assume.plugin.FailedAssumption'>, value = None, tb = None
def reraise(tp, value, tb=None):
try:
if value is None:
value = tp()
if value.__traceback__ is not tb:
> raise value.with_traceback(tb)
E pytest_assume.plugin.FailedAssumption:
E 2 Failed Assumptions:
E
E test_assume.py:16: AssumptionFailure
E >> pytest.assume(False == True)
E AssertionError: assert False
E
E test_assume.py:17: AssumptionFailure
E >> pytest.assume(100 == 200)
E AssertionError: assert False
结论
- 可以看到,第二行即使断言失败,后面的断言还是会继续执行
- 这有助于我们分析和查看到底一共有哪些断言是失败的
- 而且最后的代码也还会正常执行,比直接用assert更高效
pytest-ordering
- 场景
- 对于集成测试,通常会有上下文依赖关系的测试用例。有的需求,先执行某些需求。测试用例尽量不要有依赖。
- 安装
- pip install pytest-ordering
- pip3 install pytest-ordering -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
- 使用方式
- @pytest.mark.run(order=2)
pytest中测试用例执行顺序是从上往下执行
import pytest
def test_1():
assert True
def test_2():
assert 1 == 1
def test_2():
assert 2 == 2
运行结果:
pytest-ordering控制执行顺序
import pytest
@pytest.mark.run(order=3)
def test_1():
assert True
@pytest.mark.run(order=1)
def test_2():
assert 1 == 1
@pytest.mark.run(order=2)
def test_3():
assert 2 == 2
执行结果:
总结:
1、除了用@pytest.mark.run(order=3)这种方式指定测试用例顺序
2、还可以使用pytest.mark.third 方法指定
pytest-repeat
- 场景
- 平常在做功能测试的时候,经常会遇到某个模块不稳定,偶然会出现一些bug,对于这种问题我们会针对此用例反复执行多次,最终复现出问题来
- 自动化运行用例时候,也会出现偶然的bug,可以针对单个用例,或者针对某个模块的用例重复执行多次
- 安装
- pip install pytest-repeat
- pip3 install pytest-repeat -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
- 运行要求
- Python 2.7、3.4+或PyPy
- py.test 2.8或更高版本* 使用方式
- 使用方式
- count=2
- count 2
- pytest --html=report.html --self-contained-html -s --reruns=5 --count=2 test_request.py
重复测试直到失败(重要!!!)
- 如果需要验证偶现问题,可以一次又一次地运行相同的测试直到失败,这个插件将很有用
- 可以将pytest的 -x 选项与pytest-repeat结合使用,以强制测试运行程序在第一次失败时停止
pytest --count=1000 -x test_file.py
代码如下:
def test_example():
import random
flag = random.choice([True, False])
print(flag)
sleep(1)
assert flag
执行命令:
pytest --count 5 -x test_repeat.py
执行结果:
test_repeat.py::test_example[1-5] True
PASSED
test_repeat.py::test_example[2-5] True
PASSED
test_repeat.py::test_example[3-5] False
FAILED
================================================================= FAILURES =================================================================
____________________________________________________________ test_example[3-5] _____________________________________________________________
def test_example():
import random
flag = random.choice([True, False])
print(flag)
sleep(1)
> assert flag
E assert False
test_repeat.py:17: AssertionError
========================================================= short test summary info ==========================================================
FAILED test_repeat.py::test_example[3-5] - assert False
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
======================================================= 1 failed, 2 passed in 3.10s ========================================================
总结:执行了三次,第三次失败,就不再执行了。
@pytest.mark.repeat(count)
如果要在代码中将某些测试用例标记为执行重复多次,可以使用 @pytest.mark.repeat(count)
@pytest.mark.repeat(5)
def test_repeat():
sleep(1)
print("测试用例执行")
执行命令:
pytest test_repeat.py::test_repeat
执行结果:
test_repeat.py::test_repeat[1-5] 测试用例执行
PASSED
test_repeat.py::test_repeat[2-5] 测试用例执行
PASSED
test_repeat.py::test_repeat[3-5] 测试用例执行
PASSED
test_repeat.py::test_repeat[4-5] 测试用例执行
PASSED
test_repeat.py::test_repeat[5-5] 测试用例执行
PASSED
============================================================ 5 passed in 5.05s =============================================================
--repeat-scope
命令行参数
作用:可以覆盖默认的测试用例执行顺序,类似fixture的scope参数
- function:默认,范围针对每个用例重复执行,再执行下一个用例
- class:以class为用例集合单位,重复执行class里面的用例,再执行下一个
- module:以模块为单位,重复执行模块里面的用例,再执行下一个
- session:重复整个测试会话,即所有测试用例的执行一次,然后再执行第二次
class示例
class TestRepeat:
def test_repeat1(self):
print("test1++++++++test1")
def test_repeat2(self):
print("test2+++++++++test2")
class TestRepeat2:
def test_repeat3(self):
print("test3++++++++test3")
def test_repeat4(self):
print("test4+++++++++test4")
执行命令: pytest --count=2 --repeat-scope=class test_repeat.py
执行结果:
test_repeat.py::TestRepeat::test_repeat1[1-2] test1++++++++test1
PASSED
test_repeat.py::TestRepeat::test_repeat2[1-2] test2+++++++++test2
PASSED
test_repeat.py::TestRepeat::test_repeat1[2-2] test1++++++++test1
PASSED
test_repeat.py::TestRepeat::test_repeat2[2-2] test2+++++++++test2
PASSED
test_repeat.py::TestRepeat2::test_repeat3[1-2] test3++++++++test3
PASSED
test_repeat.py::TestRepeat2::test_repeat4[1-2] test4+++++++++test4
PASSED
test_repeat.py::TestRepeat2::test_repeat3[2-2] test3++++++++test3
PASSED
test_repeat.py::TestRepeat2::test_repeat4[2-2] test4+++++++++test4
PASSED
============================================================ 8 passed in 0.04s =============================================================
兼容性问题
- pytest-repeat不能与unittest.TestCase测试类一起使用。
- 无论--count设置多少,这些测试始终仅运行一次,并显示警告
其他
后续单独讲解pytest-xdis(重要!!!)插件的使用。