pytest
一、用例规则
pytest的用例发现步骤:
- 遍历根目录下所有除.开头的目录(比如.venv或者linux系统以.开头的隐藏文件)
- 找到以
test_开头或者以_test结尾的python文件(.py) - 遍历所有
Test开头的类 - 遍历所有
test_开头的方法 (类里面的函数)或函数(普通函数)
用例不应该有参数(参数有特殊的意义,比如fixture)和返回值(默认为None)
二、安装和使用
pip install pytest
- 代码
根目录下创建一个main.py文件,调用pytest的main函数进行执行

- 命令行
在cmd终端,在根目录下,输入pytest命令进行执行

三、执行结果
- 执行环境:系统平台、python版本、包版本信息、根目录、用例数量
- 执行过程:文件名称、用例结果、执行进度
- 失败详情:用例内容、断言提示
- 整体摘要:执行结果、结果数量(成功、失败多少条等)、耗时


| 用例执行结果缩写 | 含义 |
|---|---|
| . | 用例执行通过 |
| F | 失败(用例执行时报错) |
| E | 出错(fixture执行报错) |
| s | 跳过用例 |
| X | 预期外的通过(不符合预期) |
| x | 预期内的失败(符合预期) |
python
# 上面各种用例执行结果的测试代码
import pytest
def test_ok():
assert 1 == 1
def test_fail():
assert ["1", "3"] == ["1", "2"]
def test_error(f):
assert 1 == 1
@pytest.mark.skip("跳过")
def test_skip():
assert 1 == 1
@pytest.mark.xfail
def test_xfail():
assert 1 == 2
@pytest.mark.xfail
def test_Xfail():
assert 1 == 1
四、命令参数和配置文件
- pytest命令参数:可以使用
pytest -h来进行详细查看,下面列举一下常用的:
| 命令参数 | 说明 |
|---|---|
| <路径> | 执行指定目录/文件下所有满足的用例(不写就是默认当前目录) |
| 文件::用例 | 执行指定文件里的用例 例:pytest ./test_data.py::test_ok 表示执行当前目录下test_data文件里面的test_ok这条用例 |
| -v 或 --verbose | 增加可读性,显示详细输出(含用例名称、结果) |
| -s 或 --capture=no | 可以展示用例里面的print或日志 |
| -k | 执行用例名称包含 对应名称的用例,支持 and/or/not 逻辑,不区分大小写 例: (1)pytest -k "add" 表示执行用例名称里面带add的 (2)pytest -k "(suc or default) and not fail" 表示执行用例名称中包含suc或default,并且不包含fail的 |
| -m | 执行带特定标记的用例(配合@pytest.mark使用,支持 and/or/not 逻辑) |
| --markers | 显示所有可用的标记 |
| --fixtures | 显示所有可用的夹具 |
| -x 或 --exitfirst | 遇到首个失败用例后立即停止执行(适用于冒烟测试) |
| --maxfail=num | 失败次数达到num后停止执行,num为具体次数 |
| --lf 或 --last-failed | 仅重新执行上次失败的用例 |
| --ff 或 --failed-first | 先执行上次失败的用例,再执行其他用例 |
| -n=num | 分布式运行用例,num为进程数,需要安装pytest-xdist插件才能使用(只推荐在执行非常耗时的情况下使用,并且无强关联或依赖的用例,否则不建议使用分布式执行) |
| --reruns=num 和 --reruns-delay=n | 失败用例进行重跑,num为重试次数,n为重试等待时间(单位为秒)需要安装pytest-rerunfailures插件才能使用(如果进行了重试,在用例结果里面会显示为R,有几个R就表示重试了几次) |
| --html=report.html | 生成html测试报告,可以指定生成路径,需要安装pytest-html插件才能使用 |
| --durations=num | 显示执行的最慢的num条用例 |
- 很多pytest的默认配置,都是可以通过
pytest.ini配置文件进行修改,其中能配置的参数,再pytest -h命令里面是可以看到的(往下拉,找到[pytest],下面的参数都是配置文件里面可以自己进行自定义)

python_files,可以自定义找py文件的规则,而不是之前默认的test_开头或_test结尾的,可以自己写正则表达式addopts,可以先写好命令参数,这样就不用每次执行的时候都带上命令- 然后是关于日志相关的,可以安装
pytest-result-log插件,然后进行log相关的配置,就可以输出日志文件


五、标记(Mark)
- 用户自定义标记
只能用来筛选用例,需要先进行注册,然后再进行标记,最后进行筛选
- (1)先再根目录下创建
pytest.ini文件,然后第一行写上[pytest],然后在markers下创建自己想要的标记名

- (2)然后再想要进行的标记的用例打上装饰器
@pytest.mark.定义好的标记名,可以进行多个标记

- (3)最后通过
pytest -m 标记名来执行指定标记名的用例(这里为了更好的展示确实只运行了对应标记的用例,我们可以加上-v参数来增加输出的详细程度)

- (4)当需要筛选比较复杂的标记时,可以使用逻辑符号
and,or,not还有()来组合出想要的结果(这里表达式建议加双引号,以免产生解析错误 )

- 当然,也可以使用代码的方式运行,再
main()函数里面加上要执行的参数

- 框架内置标记
无需注册,可以直接使用,除了能筛选案例,还可以增加特殊效果
- 使用
pytest --markers可以查看用户自定义标记和框架内置标记

- 常用的框架内置标记
| 装饰器 | 说明 |
|---|---|
| @pytest.mark.skip | 无条件跳过,跳过原因可写可不写 |
| @pytest.mark.skipif | 有条件跳过,跳过原因必写,只有在表达式为True的时候才会跳过 |
| @pytest.mark.xfail | 预期内的失败 |
| @pytest.mark.parametrize | [参数化](#装饰器 说明 @pytest.mark.skip 无条件跳过,跳过原因可写可不写 @pytest.mark.skipif 有条件跳过,跳过原因必写,只有在表达式为True的时候才会跳过 @pytest.mark.xfail 预期内的失败 @pytest.mark.parametrize 参数化 (可以点击文字进行跳转查看具体用法) @pytest.mark.usefixtures 使用fixture (可以点击文字进行跳转查看具体用法)) (可以点击文字进行跳转查看具体用法) |
| @pytest.mark.usefixtures | 使用[fixture](#装饰器 说明 @pytest.mark.skip 无条件跳过,跳过原因可写可不写 @pytest.mark.skipif 有条件跳过,跳过原因必写,只有在表达式为True的时候才会跳过 @pytest.mark.xfail 预期内的失败 @pytest.mark.parametrize 参数化 (可以点击文字进行跳转查看具体用法) @pytest.mark.usefixtures 使用fixture (可以点击文字进行跳转查看具体用法)) (可以点击文字进行跳转查看具体用法) |

六、参数化(Parametrize)
前面提到过,用例是不能有参数的,参数有另外的含义(进行参数化,或者使用fixture),这里主要讲的是框架内置标记@pytest.mark.parametrize
- 第一个参数是参数名:字符串形式的参数名(多个参数用逗号分隔),也可以是列表或元祖(里面都是字符串)
- 第二个参数是参数值 :可迭代的测试数据集(列表或元组)

- 可选参数
ids:可迭代对象,允许自定义测试用例ID名,其中里面的数量要与参数值列表的长度一致

- 可选参数
indirect:当设置为True时,所有 参数名被视为 fixture 名称,参数值通过request.param传递给该fixture,实现预处理(比如对数据进行格式转换,资源初始化等)。也可以传递一个列表或元组(里面是要视为 fixture 的参数,即只针对特定某一个或几个参数进行处理,其他参数当做普通参数传递) - 下面演示个使用例子(使用csv数据文件进行动态参数化测试):
(1)首先创建一个csv文件,准备点数据

(2)配置pytest.ini文件
(3)编写测试代码

(4)观看测试结果

(5)只针对部分参数视为 fixture

七、夹具(Fixture)
fixture主要是在用例执行前进行前置(Setup)和后置(Teardown)操作的,通过装饰器@pytest.fixture来设置,主要有以下几个参数:
scope:控制作用域,默认为 function(优先级顺序:session > package > module > class > function)- function:每个测试函数或方法执行一次
- class:每个测试类执行一次
- module:每个模块执行一次
- package:每个包执行一次
- session:整个测试会话执行一次
autouse:是否自动使用,如果为True,则无需显示调用,会自动使用(受作用域控制),默认为Falseparams:参数化,实现数据驱动测试,有几个值,对应用到这个fixture的用例就执行多少次ids:配合parms使用,给用例取名称,数量要和params的一致name:给 fixture 重命名,后续使用的时候就使用别名
- 使用方式1:把 fixture名 当做参数传入

- 使用方式2:使用
@pytest.mark.usefixtures装饰器,里面传 fixture名

- 使用多个fixture



- 使用
request参数,使用request.getfixturevalue("要获取返回值的fixture名"),来获取@pytest.mark.usefixtures里面的fixture的返回值

- 嵌套使用 fixture

- 自动使用,作用域,以及别名的使用

- 参数化(如果使用
ids参数,它的长度要与参数列表长度一致)

- 使用
conftest.py进行全局数据共享




- 总结(fixture和conftest执行顺序)
- 作用域优先级
- fixture按作用域从高到低执行:session > package > module > class > function
- 从外到内依次加载,即根目录的conftest.py优先执行,然后是子目录的conftest.py
- 如果存在同名fixture,子目录的优先级高于父目录(即会进行覆盖)
- 自动调用(autouse=True)优先
- 自动调用的fixture优先于同作用域的手动调用fixture执行
- 同是自动调用时,按fixture函数名称的字母排序执行
- 依赖关系触发
- 被其他fixture依赖的fixture会优先执行,即使其作用域较低
- 禁止高作用域fixture依赖低作用域fixture(如session级依赖function级)
八、插件管理
- 启用和禁用
-p abc:表示启用abc插件
-p no:abc:表示禁用abc插件 - 插件的使用方式
(1)参数(命令参数)
(2)配置文件(pytest.ini里的addopts)
(3)fixture
(4)mark(比如pytest-order,使用的时候就是@pytest.mark.order()的形式) - pytest插件库地址:https://docs.pytest.org/en/stable/reference/plugin_list.html
- 常用第三方库:
| 插件 | 功能 |
|---|---|
| pytest-xdist | 分布式执行用例(多进程) |
| pytest-cov | 生成代码覆盖率报告 |
| pytest-html | 生成html测试报告 |
| allure-pytest | 集成Allure框架生成详细测试报告 |
| pytest-rerunfailures | 自动失败重试用例 |
| pytest-order | 自定义用例执行顺序 |
九、使用Allure生成测试报告
- Allure下载:https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/,找一个能兼容pytest版本的zip包下载(这里就以windows举例了)
- 解压后,添加到环境变量(在终端敲
allure --version,如果没有报错,说明成功)


- 安装
allure-pytest
pip install allure-pytest
- 使用allure生成报告
先导入allure包,然后选择对应的装饰器
epic 相当于 项目
feature 相当于 模块
story 相当于 功能
title 相当于 用例

pytest --alluredir=./result --clean-alluredir(其中./result表示要把数据生成到哪个目录下,--clean-alluredir表示每次生成前都清除之前的历史数据)

使用pytest命令运行完后,会生成一堆json文件

然后再终端,输入allure generate ./result -o ./report --clean来生成html报告(其中./result表示上一步生成的json文件路径,-o ./report表示输出报告到哪个路径下,--clean表示每次都先删掉历史数据再重新生成),然后使用浏览器打开index.html文件


这里就可以看到刚刚我们用allure的装饰器,这里就按对应的层级展示,非常直观,找起对应的用例十分方便
