一、pytest简介
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常用命令
***查看帮助信息*** 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实用插件
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-htmlpip 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-rerunfailurespip install pytest-rerunfailures pytest --reruns 5 -s #运行失败的fixture或setup_class也将重新执行pytest -s demo_xxx.py --reruns 5pytest -s demo_xxx.py --reruns 5 --reruns-delay 1 #重跑之前等待1s
pytest-assume
pytest-assume实现用例的多重校验,虽然assert也可以写多个校验条件,但是前一个条件失败,后面的校验就不会执行,而 pytest-assume断言即使前面一个断言失败,后面的断言也会继续执行。
安装pytest-assumepip install pytest-assume
pytest-ordering
对于存在上下文依赖的测试,有时候可能需要设定一些特定执行顺序,pytest的ordering插件,就很好的解决了这个问题
安装pytest-orderingpip 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
五、pytest的setup和teardown函数作用
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----------
六、pytest的setup_module\setup_class和teardown_module\teardown_class函数作用
运行于测试类初始化以及结束时,即:在一个测试内只运行一次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的配置文件一般放在测试目录下,名称为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_开头的方法 -可自定义
八、pytest跳过测试用例
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"