pytest是一个非常成熟的全功能的Python测试框架。
pytest框架特点:
简单灵活,非常容易上手
支持参数化
支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)
pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等
测试用例的skip和xfail处理
可以与jenkins集成
report框架----allure 也支持了pytest
pytest安装
pip install -U pytest
查看版本或查看是否已安装:
demo1测试通过
import pytest
'''
1、测试方法要以test开头
'''
def test_testdemo1():
print(">>>>>test_pass>>>>>>>")
assert 1 == 1
if __name__ == '__main__':
pytest.main()
#命令行执行用例文件
#pytest test_mod.py
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: C:\github\xxx\xxxx
plugins: celery-4.3.0
collected 1 item
test_a1.py . [100%]
============================== 1 passed in 0.12s ==============================
Process finished with exit code 0
demo2测试不通过
import pytest
'''
1、测试方法要以test开头
'''
def test_testdemo2():
print(">>>>>test_fail>>>>>>>")
assert 1 == 2
if __name__ == '__main__':
pytest.main()
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: C:\github\xxxxx\xxxx
plugins: celery-4.3.0
collected 1 item
test_a1.py F [100%]
================================== FAILURES ===================================
_______________________________ test_testdemo2 ________________________________
def test_testdemo2():
print(">>>>>test_fail>>>>>>>")
> assert 1 == 2
E assert 1 == 2
test_a1.py:24: AssertionError
---------------------------- Captured stdout call -----------------------------
>>>>>test_fail>>>>>>>
=========================== short test summary info ===========================
FAILED test_a1.py::test_testdemo2 - assert 1 == 2
============================== 1 failed in 0.14s ==============================
***查看帮助信息***
pytest --version # 查看当前已安装版本
pytest --fixtures #显示内置函数参数
pytest --help #查看帮助信息
***用例执行控制***
pytest -x # 遇到失败用例停止测试
pytest --maxfail=2 # 出现2个用例失败终止测试
pytest test_XX.py # 指定运行的测试文件
pytest test/ # 指定测试目录
pytest -k "MyClass and not method" #通过关键字表达式过滤需要执行的用例,条命令会匹配文件名、类名、方法名匹配表达式的用例,这里这条命令会运行 TestMyClass.test_1, 不会执行 TestMyClass.test_method_1
pytest test_xx.py::test_xxx #通过 node id 指定测试用例,即执行test_xx.py用例文件的test_xxx方法,nodeid由模块文件名、分隔符、类名、方法名、参数构成
pytest -m slow #通过标记表达式执行,这条命令会执行被装饰器 @pytest.mark.slow 装饰的所有测试用例
pytest --pyargs pkg.test #这条命令会自动导入包 pkg.test,并执行该包所在的目录下面的用例。
pytest test_se.py -s #-s 加上-s参数可以在运行pytest时将print语句输出到控制台
pytest-xdist
pytest-xdist可以实现多进程运行测试用例,在测试用例比较多的情况下可以有效缩短脚本的测试执行时间。
安装pytest-xdist:
pip install -U pytest-xdist
使用pytest-xdist运行测试用例:
pytest test_se.py -n NUM --NUM为进程数
pytest-html
pytest-HTML是一个插件,pytest用于生成测试结果的HTML报告。
安装pytest-html
pip install pytest-html
使用pytest-htm生成测试结果报告
pytest --html=report.html --执行当前目录下的用例文件
指定报告生成的路径
pytest --html=./report/report.html
将css样式合并到html里
pytest --html=report.html --self-contained-html
pytest-rerunfailures
pytest-rerunfailures失败用例重跑
命令行参数:--reruns n(重新运行次数),--reruns-delay m(等待运行秒数)
装饰器参数:reruns=n(重新运行次数),reruns_delay=m(等待运行秒数) @pytest.mark.flaky(reruns=5)
安装pytest-rerunfailures
pip install pytest-rerunfailures
pytest --reruns 5 -s #运行失败的fixture或setup_class也将重新执行
pytest -s demo_xxx.py --reruns 5
pytest -s demo_xxx.py --reruns 5 --reruns-delay 1 #重跑之前等待1s
pytest-assume
pytest-assume实现用例的多重校验,虽然assert也可以写多个校验条件,但是前一个条件失败,后面的校验就不会执行,而 pytest-assume断言即使前面一个断言失败,后面的断言也会继续执行。
安装pytest-assume
pip install pytest-assume
pytest-ordering
对于存在上下文依赖的测试,有时候可能需要设定一些特定执行顺序,pytest的ordering插件,就很好的解决了这个问题
安装pytest-ordering
pip install pytest-ordering
@pytest.mark.run(order=2)
def test_demo1():
print ("first test")
assert True
@pytest.mark.run(order=1)
def test_demo2():
print ("second test")
assert True
原执行顺序为test_demo1>>test_demo2
加上@pytest.mark.run(order=X)执行的顺序变为test_demo2>>test_demo1
setup和teardown函数运行于测试方法的开始与结束时,即:运行一次测试函数前调用setup函数,测试结束后调用teardown函数。setup()/teardown()是函数级别的。
import pytest
class TestDemo1:
def setup(self):
print("------->setup_method------------")
def teardown(self):
print("------->teardown_method----------")
def test_demo1(self):
print("------->test_a-----------")
assert 1
platform win32 -- Python 3.5.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: E:\PyProject\TestDemo1
collected 1 item
source\testDemo1.py ------->setup_method------------
------->test_a-----------
.------->teardown_method----------
运行于测试类初始化以及结束时,即:在一个测试内只运行一次setup_class和teardown_class。
def setup_module(self): print("=======1111111========") def teardown_module(self): print("=======1111111========") import pytest class Test_ABC: @classmethod def setup_class(self): print(">>>>>>setup_class_method>>>>>>>>") @classmethod def teardown_class(self): print(">>>>>>teardown_class_method>>>>>") def setup(self): print(">>>>>>setup_method>>>>>>") def teardown(self): print(">>>>>>teardown_method>>>>>>") def test_a(self): print(">>>>test_a>>>>>") assert 1==1 def test_b(self): print(">>>>>test_b>>>>>") assert 1==1
platform win32 -- Python 3.5.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: C:\github\YZhttprunner\YZhttprunner
plugins: celery-4.3.0
collected 2 items
test_a1.py =======setup_module========
>>>>>>setup_class_method>>>>>>>>
>>>>>>setup_method>>>>>>
>>>>test_a>>>>>
.>>>>>>teardown_method>>>>>>
>>>>>>setup_method>>>>>>
>>>>>test_b>>>>>
.>>>>>>teardown_method>>>>>>
>>>>>>teardown_class_method>>>>>
=======teardown_module========
pytest的配置文件一般放在测试目录下,名称为pytest.ini的文件,命令行运行时会使用该配置文件中的配置.
#配置pytest命令行运行参数
[pytest]
addopts = -s ... # 空格分隔,可添加多个命令行参数 -所有参数均为插件包的参数配置测试搜索的路径
testpaths = ./testcase # 即当前目录下的testcase文件夹 -可自定义
#配置测试搜索的文件名称
python_files = test*.py
#当前目录下的testcase文件夹下,以test开头,以.py结尾的所有文件 -可自定义
配置测试搜索的测试类名
python_classes = Test_*
#当前目录下的testcase文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类 -可自定义
配置测试搜索的测试函数名
python_functions = test_*
#当前目录下的testcase文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类内,以test_开头的方法 -可自定义
1、使用@pytest.mark.skip()装饰测试方法,运行测试时将会跳过该方法不执行。
#跳过测试函数的最简单方法是使用跳过装饰器标记它,可以传递一个可选的原因
@pytest.mark.skip(reason='misunderstood the API')
def test_demo1():
....
2、在测试方法中设置强制跳过pytest.skip(reason)
def test_demo1()::
if not valid_config():
pytest.skip("unsupported configuration")
3、设置跳过整个模块级别pytest.skip(reason,allow_module_level = True)
import pytest
if not pytest.config.getoption("--custom-flag"):
pytest.skip("--custom-flag is missing, skipping tests", allow_module_level=True)
4、有条件地跳过某些内容,则可以使用skipif(可以装饰类和方法)
'''
如果当前环境是python3.6以下版本就跳过用例
'''
import sys
@pytest.mark.skipif(sys.version_info < (3,6),
reason="当前python环境版本小于3.6跳过测试用例")
def test_demo1():
...
'''
如果当前环境是python3.6以下版本,则跳过该类的所有测试方法
'''
@pytest.mark.skipif(sys.version_info < (3,6),
reason="requires python3.6 or higher")
class TestCalls(object):
def test_demo1(self):
"will not be setup or run under 'python3.6' platform"
欢迎大家关注我的订阅号,会定期分享一些关于测试相关的文章,有问题也欢迎一起讨论学习!