Pytest 测试框架
🍰 PyTest是Python的一种单元测试框架,与Python自带的UnitTest测试框架类似,但使用比UnitTest更简洁,效率更高。
1 规则说明
- 规则说明
- PyTest是Python2默认自带的,在Python3中则是独立的,需使用
pip install pytest进行安装。 - 运行规则
- 查找当前目录及子目录中
test_*.py或*_test.py文件。 - 找到所有的文件后,执行文件中以
test开头的所有函数。
- 查找当前目录及子目录中
- 用例设计规则
- 测试文件以
test_开头,或以_test结尾,测试类以Test开头,并且不能带有init方法。 - 测试函数和方法以
test_开头,断言用assert,所有的package包必须带__init__.py文件。
- 测试文件以
- PyTest是Python2默认自带的,在Python3中则是独立的,需使用
1 | |
1-1 用例执行规则
- 用例执行规则
- 执行某个目录下所有的用例:
pytest FolderName/。 - 执行某个文件中的所有用例:
pytest FileName.py。 - 遇到错误时,停止正在执行的测试用例:
pytest -x FileName.py。 - 用例错误个数达到指定数量时,停止测试:
pytest --maxfail=num。 - 按照关键字进行模糊匹配,匹配名称不区分大小写:
pytest -k "xxx"。 - 简单结果:
pytest -q FileName.py,--quiet decrease verbosity。 - 按节点运行
- 每个测试用例都分配了唯一的nodeid,nodeid由模块名和说明符组成。
- 模块名和说明符以
::间隔,说明符可以包含类名、函数名和标记参数。
- 标记表达式运行用
@pytest.mark.slow修饰器修饰的所有用例:pytest -m slow。
- 执行某个目录下所有的用例:
1 | |
1-2 PyCharm运行方式
- PyCharm运行方式
- 默认以Autodetect形式运行,可以通过修改PyCharm设置来改变运行方式。
- File—>Setting—>Tools—>Python Integrated Tools—>Default test runner。
- PyTest兼容UnitTest,用UnitTest框架编写的测试用例也能用PyTest框架运行。
1 | |
2 跳过用例
- 跳过用例
- 装饰器
@pytest.mark.skip():标记测试用例为跳过状态,并提供跳过原因。 - 装饰器
@pytest.mark.skipif():当指定的条件满足时,即为True,跳过测试用例并提供跳过原因。 - 装饰器
@pytest.mark.xfail():标记测试用例为预计失败,实际运行时会被忽略,不影响测试结果。 - 函数
pytest.skip():在测试用例执行期间,强制跳过当前测试用例并提供跳过原因,类似于break跳出循环。 - 函数
pytest.xfail():标记已知存在问题但尚未修复的用例,依赖于被标记成xfail用例的其他用例也会跳过。 - 自定义跳过标识
- 将
pytest.mark.skip()或pytest.mark.skipif()赋值给一个自定义标识变量,不同模块之间进行共享。 - 若有多个模块的用例需要用到同个标识变量,可单独文件管理通用的标识变量,适用于整个测试用例集。
- 将
- 函数
pytest.importorskip():某用例依赖于特定模块,但当前环境中该模块不可导入时使用该函数跳过用例。
- 装饰器
2-1 @pytest.mark.skip()
- @pytest.mark.skip()
- 用在跳过单个用例(函数用例)、类用例、类方法用例上,如果加在类用例上,类里面的所有测试用例都不会被执行。
- 可选参数reason,代表跳过原因,会在执行结果中打印,可选参数condition,用于定义在特定条件下跳过测试用例。
pytestmark=pytest.mark.skip(),pytestmark是pytest中一个特殊的不可更改变量名,用于设置模块级别的标记。- 如果想在模块级别跳过测试用例,但不使用pytestmark,则可以使用其他变量名,注意需要使用装饰器来进行标记。
(1) test_mark_skip.py
1 | |
(2) test_skip_module.py*
1 | |
2-2 @pytest.mark.skipif()
- @pytest.mark.skipif()
- 可选参数reason,用于添加关于跳过测试用例的原因说明。
- 可选参数condition,定义特定条件下是否跳过用例的表达式。
1 | |
2-3 @pytest.mark.xfail()
- @pytest.mark.xfail()
- 标记测试用例为预期失败状态,预期失败即该用例的目标是失败的。
- 参数run用于控制在特定的条件下,是否执行标记为xfail的测试用例。
- 参数reason用于提供预期失败的原因说明,参数raises则指定预期抛出的异常类型。
- 参数strict用于控制测试用例在预期失败时,是否以失败的标记显示在测试报告中。
1 | |
2-4 pytest.skip()
- pytest.skip()
- 用于跳过特定测试用例的执行,可以在测试函数、方法或类上使用。
- 通常用于某功能尚未实现,但已编写了测试用例,暂时跳过这些用例的情况。
- 或者测试用例依赖于某些条件,但这些条件当前不满足,因此跳过这些用例。
(1) test_skip_msg.py
1 | |
(2) test_skip_allow.py
1 | |
2-5 pytest.xfail()
- pytest.xfail()
- 用于标记测试用例为预期失败状态,预期失败即该测试用例的目标是失败的。
- 参数reason提供预期失败的原因说明,参数raises则指定预期抛出的异常类型。
1 | |
2-6 自定义跳过标识
1 | |
2-7 pytest.importorskip()
- pytest.importorskip()
pytest.importorskip(modname: str, minversion: Optional[str] = None, reason: Optional[str] = None)- 参数列表:modname-模块名、minversion-版本号、reason-跳过原因,模块名必选,版本号和跳过原因都是可选的。
1 | |
3 assert断言
- assert断言
- 即实际结果和期望结果的比对,符合预期就pass,不符合则failed。
- PyTest允许使用标准的Python断言assert来验证测试中的期望和值。
1 | |
3-1 异常信息
1 | |
3-2 异常断言
1 | |
- 异常类型
- 要判断抛出的异常是否预期,例如
1/0抛出的异常为:ZeroDivisionError: division by zero。 - 断言该异常,通常是断言异常的type和value值,type是ZeroDivisionError,value是division by zero。
- 要判断抛出的异常是否预期,例如
1 | |
3-3 常用断言
- 常用断言
assert xx:判断xx为真。assert not xx:判断xx不为真。assert a in b:判断b包含a。assert a == b:判断a等于b。assert a != b:判断a不等于b。
1 | |
4 用例运行级别
- 用例运行级别
- 模块级:setup_module、teardown_module,在所有用例前后只执行一次。
- 函数级:setup_function、teardown_function,在所有用例前后都执行一次。
- 类级别:setup_class、teardown_class,在类中的所有用例前后只执行一次。
- 类方法级:setup_method、teardown_method,在类中的所有用例前后都执行一次。
- 类方法细化级:setup、teardown,运行规则与类方法级相同,在每个用例前后都执行一次。
4-1 模块级
1 | |
4-2 函数级
1 | |
4-3 类级别
1 | |
4-4 类方法级
1 | |
4-5 类方法细化级
1 | |
4-6 类和方法混合
1 | |
4-7 模块和类混合
1 | |
5 fixture预置条件
- fixture预置条件
- 相比用例运行级别的setup和teardown,fixture的命名方式更为灵活。
@pytest.fixture(scope="function", params="None", autouse=False, ids=None, name=None)- scope:类似于作用域,默认为function,还可以是class、module、session、package。
- autouse:默认为False,用例手动调用该fixture,若为True则作用域内的用例自动调用。
- name:默认的装饰器名称,同一模块的fixture相互调用时可以使用不同的name进行命名。
1 | |
5-1 conftest.py
- conftest.py
- 配置文件里可以实现数据共享(多个
.py文件的预置操作),不用import,PyTest就能自动查找配置。 - 注意:
conftest.py配置脚本名称固定,与运行的用例要在同个package下且有__init__.py文件。
- 配置文件里可以实现数据共享(多个
(1) conftest.py
1 | |
(2) test_conftest.py
1 | |
5-2 scope实现setup
- scope实现setup
- fixture的参数
scope="module"可以实现多个.py跨文件共享前置。 - module作用于整个
.py文件,用例调用时,参数写上函数名称即可。 scope="module"可以理解为在测试用例中加上前置条件,类似setup。
- fixture的参数
(1) 用例全局调用
1 | |
(2) 部分用例调用
1 | |
5-3 yield实现teardown
1 | |
(1) 用例异常
1 | |
(2) setup异常
1 | |
(3) 配合with使用*
1 | |
5-4 addfinalizer终结函数
1 | |
5-5 调用fixture的3种方法
- 调用fixture的3种方法
- 函数或类的方法中传fixture的函数参数名称。
- 用装饰器
@pytest.mark.usefixtures()修饰。 - 设置fixture的参数为
autouse=True来自动使用。
(1) 用例fixture传参
1 | |
(2) 装饰器usefixtures
1 | |
(3) 设置autouse=True
1 | |
- 设置autouse=True
- start设置scope为module级别,在当前用例模块中只执行一次,
autouse=True自动使用。 - open_home设置scope为function级别,每个用例前都调用一次,
autouse=True自动使用。
- start设置scope为module级别,在当前用例模块中只执行一次,
1 | |
6 自定义标记mark
- 自定义标记mark
- 自定义标记可以将一个Web项目划分为多个模块,然后指定模块名称进行执行。
- APP自动化时,若想让Android与IOS共用一套代码,也可以使用标记指定名称。
1 | |
- 用例执行规则
- 命令窗口下只运行用tagname标记的测试用例时,可以使用命令:
pytest -v -m tagname。 - 若不想执行tagname标记的用例,文件内容对应修改,使用命令:
pytest -v -m "not tagname"。
- 命令窗口下只运行用tagname标记的测试用例时,可以使用命令:
1 | |
6-1 重写注册标签
- 重写注册标签
- 根目录创建
conftest.py文件,在文件中重写pytest_configure函数的方式可以注册标签。 - 函数名pytest_configure和参数config是固定的,唯一需要变更的是注册标签的名字和描述。
- 根目录创建
(1) conftest.py
1 | |
(2) test_mark.py
1 | |
6-2 配置注册标签
- 配置注册标签
- 还有一种更加便捷的注册标签的方式,即在
pytest.ini配置文件中进行语法配置。 - 同样在根目录创建
pytest.ini文件,只需要在文件中编写如下配置内容就可以了。
- 还有一种更加便捷的注册标签的方式,即在
(1) pytest.ini
1 | |
(2) test_mark.py
1 | |
6-3 灵活挑选用例
(1) pytest.ini
1 | |
(2) test_mark_flexible.py
1 | |
7 用例的参数化设置
- 用例的参数化设置
- 参数化方式有两种:parametrize参数化和fixture参数化。
- 使用
@pytest.mark.parametrize装饰器实现用例的参数化。 - parametrize还可以结合内置函数,标记测试实例进行参数化。
7-1 parametrize
1 | |
(1) 结合内置函数
1 | |
(2) 参数组合使用
1 | |
(3) 函数传参操作
1 | |
7-2 fixture传参
1 | |
(1) 传两个参数
1 | |
(2) 多个fixture
1 | |
8 命令行参数的配置
- 命令行参数的配置
- 在
conftest.py文件中添加命令行选项,命令行传入参数--cmdopt,用例需用到时即调用cmdpot函数。 - 配置文件
pytest.ini也可以改变pytest的运行方式,是一个固定文件,读取配置信息,按指定方式运行。 - PyTest框架的部分文件说明
conftest.py:参数用例的一些fixture配置。setup.cfg:ini格式文件,影响setup.py的行为。pytest.ini:主配置文件,改变PyTest的默认行为。tox.ini:与pytest.ini类似,使用tox工具时才用。__init__.py:识别该文件所在的文件夹为Python的package包。
- 在
8-1 conftest.py
1 | |
(1) 不带参数执行
1 | |
(2) 带上参数执行
1 | |
8-2 pytest.ini配置
- pytest.ini配置
- 一个项目有一个
pytest.ini文件即可,放在项目的根目录下。 - 命令窗口下使用
pytest --help指令,可以查看到pytest.ini文件中的设置选项。 pytest.ini文件不能带中文注释,否则运行将报错:UnicodeDecodeError: 'gbk'...illegal multibyte。- addopts参数默认更改命令行选项,例如:执行完用例需要生成报告,使用命令
pytest --html=report.html。 - 将生成报告的命令加入
pytest.ini文件中,下次直接执行pytest指令,PyTest就会默认带上这些新增的参数。
- 一个项目有一个
1 | |
- mark标记
- 使用mark标记功能,对后续分类测试用例十分有用,将自定义标记写入
pytest.ini文件中,方便管理。 - 命令窗口对应
pytest.ini文件所在的文件夹下,输入pytest --markers命令可以查看到已定义的标记。
- 使用mark标记功能,对后续分类测试用例十分有用,将自定义标记写入
1 | |
- 禁用xpass*
- 设置
xfail_strict = true可以让标记为@pytest.mark.xfail但实际通过的用例被报告为失败。 - 在
test_xpass.py实例中,test_b和test_c都标记为失败,这里希望b和c用例不用执行就显示xfail。
- 设置
(1) pytest.ini
1 | |
(2) test_xpass.py
1 | |
9 生成html测试报告
- 生成html测试报告
- pytest-html:PyTest用于生成测试结果的html报告插件,
pip install pytest-html进行安装。- 执行方法:
pytest --html=report.html,当前目录中生成report.html报告文件。 - 指定执行某个
.py文件生成报告:pytest test_filename.py --html=report.html。 - 生成报告到当前文件夹的report目录中:
pytest test_filename.py --html=./report/report.html。 - 上述方法生成的报告,css独立,分享报告时样式将丢失,为更好展示报告,可将css样式合并到html中。
- 让
report.html报告独立显示,可使用命令:pytest --html=report.html --self-contained-html。 - 用例执行失败重跑需依赖pytest-rerunfailures插件,命令安装:
pip install pytest-rerunfailures。- 重跑n次:
pytest --reruns n,失败才重跑,成功用例使用无效。 - 重跑n次,每次间隔m秒:
pytest --reruns n --reruns-delay m。
- 重跑n次:
- 执行方法:
- allure:report框架,支持Python的PyTest、Java的JUnit、TestNG等框架,可以集成到Jenkins上。
- pytest-html:PyTest用于生成测试结果的html报告插件,
9-1 conftest.py
1 | |
9-2 test_screenshot.py
1 | |
Pytest 测试框架
https://stitch-top.github.io/2023/03/03/zi-dong-hua/at02-pytest/at01-pytest-ce-shi-kuang-jia/