--no-print-logs disable printing caught logs on failed tests.
--log-level=LOG_LEVEL logging level used by the logging module
--log-format=LOG_FORMAT log format as used by the logging module.
--log-date-format=LOG_DATE_FORMAT log date format as used by the logging module.
--log-cli-level=LOG_CLI_LEVEL cli logging level.
--log-cli-format=LOG_CLI_FORMAT log format as used by the logging module.
--log-cli-date-format=LOG_CLI_DATE_FORMAT log date format as used by the logging module.
--log-file=LOG_FILE path to a file when logging will be written to.
--log-file-level=LOG_FILE_LEVEL log file logging level.
--log-file-format=LOG_FILE_FORMAT log format as used by the logging module.
--log-file-date-format=LOG_FILE_DATE_FORMAT log date format as used by the logging module.
======================== short test summary info =====================
FAILED test_demo.py::test_a2
======================== 1 failed, 1 passed in 4.18s ===============
1 环境与准备
1.1 说明
基于 httprunner 框架的用例结构,我自己开发了一个 pytest + yaml 的框架,那么是不是重复造轮子呢? 不可否认 httprunner 框架设计非常优秀,但是也有缺点,httprunner3.x 的版本虽然也是基于 pytest 框架设计,结合 yaml 执行用例,但是会生成一个py文件去执行。 在辅助函数的引用也很局限,只能获取函数的返回值,不能在 yaml 中对返回值重新二次取值。 那么我的这个框架,就是为了解决这些痛点。。。。 完整视频教程地址https://study.163.com/course/courseMain.htm?courseId=1213419817&share=2&shareId=480000002230338 (视频收费:包含 pytest + yaml 框架开发教学和使用教学, 买课程的学员可以用新版本更多强大功能,咨询wx:283340479)
本插件可以实现以下优势:
联系我们:
1.2 环境准备
最低版本要求 Python 3.8 版本或以上版本. 目前兼容 python3.8, python3.9, python3.10版本 (低于 python3.8 版本无法安装此插件,低版本python不做适配) Pytest 7.2.0+ 最新版可以有最佳体验
pip 安装插件即可使用,不需要下载源码
2 快速开始
2.0 快速创建项目demo
使用
--start-project
命令, 帮助初学者快速创建项目 demo 结构, 并自动创建几个简单的用例。执行以下命令
运行日志
执行完成会自动生成以下文件
test_extract.yml 内容
自动创建 pytest.ini 文件,并添加 2 个配置参数
看到项目结构生成后,仅需执行 pytest 命令即可运行用例
2.1 第一个hello world
yaml 用例编写规则,跟 pytest 识别默认规则一样,必须是 test 开头的,以
.yml
结尾的文件才会被识别注意: v1.1.4 之后的新版本可以识别 .yml 和 .yaml 2种后缀格式, 并且是 test 开头或者 test 结尾的文件 四种文件都能被识别成用例:test*.yml 、 test*.yaml 、*test.yml、 *test.yaml
新建一个
test_hello.yml
文件用例整体结构延续了 httprunner 框架的用例结果,主要是为了大家快速上手,减少新的规则学习
从上面的运行可以看出,request 不是必须的,我们可以直接调用python内置函数print 去打印一些内容了。
2.2 一个简单的 http 请求
以
http://www.example.com/
get 请求示例 test_get_demo.yml命令行输入 pytest 后直接运行
运行规则规则跟 pytest 完全一致,使用 pytest 的命令行运行用例
2.3 一个简单的 post 请求
test_post_demo.yml
2.4 validate校验
比如返回的response内容
校验可以支持 response 取值对象:status_code, url, ok, headers, cookies, text, json, encoding 其中返回的是 json 格式,那么可以支持
body.keyname.keyname
$..keyname
xx(.+?)xxx
如果返回的不是 json 格式,那么可以用正则取值
2.5 变量的声明与引用
变量的声明,只支持在config 声明整个yml文件的全局变量(不支持单个step的变量,减少学习成本) 在 httprunner 里面变量引用语法是
$user
, 引用函数是${function()}
我这里统一改成了一个语法变量引用${var}
和 引用函数${function()}
(表面上没多大变量,实际上功能强大了很多,使用了强大的 jinja2 模板引擎) 可以在引用函数后继续对结果操作, 这就解决了很多人提到了函数返回一个 list,如何在 yaml 中取某一个值的问题运行结果
3.用例编写
3.1 参数关联
3.1.1 extract 提取接口返回参数关联
在自动化用例中,我们经常会看到有人提问,上一个接口的返回的结果,如何取出来给到下个接口的入参。 我们用 extract 关键字提取接口的返回结果(需要更新v1.0.2版本)。
举个例子 用个post请求
http://httpbin.org/post
比如我需要提取返回接口里面的url参数,那么我们用extract 关键字
test_demo.yml 文件示例
3.1.2 引用提取结果
上一个接口提取到了url 变量,接下来在下个接口中引用
${url}
于是看到请求报文中引用成功
3.1.3 extract 提取结果二次取值
在yaml中对返回值重新二次取值 对于提取的结果,我想继续取值,比如他是一个字符串,在python中可以用切片取值 那么,在 yaml 中如何实现?
我重新设计的这个框架中,就可以支持python语法,直接用切片取值
请求报文
extract 取值语法
校验方式可以支持response取值对象:status_code, url, ok, headers, cookies, text, json, encoding 其中返回的是json格式,那么可以支持
如果返回的不是json格式,那么可以用正则取值
当一个用例用到多组测试数据的时候,我们必然会用到参数化,接下来看下如何在yaml文件中实现参数化
3.2 全局 Token 管理
我们在使用自动化测试框架的时候,经常会遇到一个需求,希望在全局用例中,仅登录一次,后续所有的用例自动带上请求头部token 或者cookies。
3.2.1 登录fixture 功能
我在 pytest + yaml 框架框架中封装了一个内置 fixture 叫
requests_session
, 它的作用范围是scope="session"
,也就是全部session用例会话中仅实例化一次。 现在我只需在conftest 中写一个登录的fixture功能,获取token后添加到requests_session
头部上面代码中,我用login() 函数实现登录功能,这里返回一个随机值,主要是为了验证我只调用了一次登录方法 接着我写2个yaml文件(注意,yaml文件中也不需要重复去添加请求头部了)
test_get_demo.yml
test_post_demo.yml
3.2.2 运行用例
在命令行中输入
pytest
运行 抓包看发过去的请求于是可以看到,在2个用例中都自动带上了请求头部参数。 (登录cookies的使用原理也是一样的,登录后cookies一般会自动保持)
3.2.3 其它需求
那有些接口不需要登录怎么办呢?比如登录和注册的接口,是不需要带上登录token的,那不能一刀切。 我除了默认用到一个
requests_session
全局的内置fixture,还预留了2个在yaml文件中切换到指定fixture功能,
requests_module
和requests_function
后续会实现,先实现大需求,解决大部分人遇到的痛点问题!3.2.4 requests_module 和 requests_function
那有些接口不需要登录怎么办呢?比如登录和注册的接口,是不需要带上登录token的。
除了默认用到一个requests_session 全局的内置fixture,还预留了2个
接下来看下如何在用例中使用test_register.yml
在config 中传入 fixtures参数,requests_module 是每个yaml文件中用一个请求会话(会保持cookies) requests_function 作用是每个用例中用一次,每个用例独立运行,不保持cookies。
3.2.5 自定义 fixtures
pytest 的核心功能是学会灵活使用fixtures, 那么我们的这个插件也是可以支持在用例中调用fixtures功能的。
在conftest.py 文件中写你需要实现的fixture 功能, 设置使用范围为
scope="function"
函数级别在 yaml 文件中引用 fixture
于是运行结果可以看到,每个用例前后都会执行
如果想整个yaml 文件中仅运行一次,那么conftest.py 文件中写你需要实现的 fixture 功能, 设置使用范围为
scope="module"
模块级别于是看到运行的时候,仅在yaml 文件的全部用例中只执行一次
3.2.6 多个fixtures的使用
当 yaml 中的用例需要用到多个fixtures时, 支持2种格式
格式一: 逗号隔开
格式二: 用 list
requests_module 和 requests_function 内置 fixture 功能在 v1.1.1 版本实现, 版本太低的请及时更新版本。
3.3 parameters 参数化
3.3.1 参数化数据结果
当一个用例用到多组测试数据的时候,我们必然会用到参数化,接下来看下如何在yaml文件中实现参数化 用例参数化的实现,我设计了2种实现方式
参数化方式1:
参数化方式2:
3.3.2 使用 fixtures 功能实现参数化
基本实现原理参考 pytest 框架的参数化实现
在上面的用例中,只需要关注参数化的2个变量test_input, expected 也就是在测试用例中传的2个值,可以理解为用例的2个fixture参数 还需要关注测试数据,测试数据结构必须是list,里面是可以迭代的数据,因为有2个变量,所以每组数据是2个值。
在yaml文件中
示例 test_params.yml
运行yaml文件
会自动生成2个测试用例
3.3.3 parameters 实现参数化
第二种实现方式,可以在fixtures 中传变量,但是测试数据必须是字典类型,从字典的key中动态读取变量名称 test_params_2.yml
运行yaml文件
以上2种实现参数化方式效果是一样的
3.4 yaml 中调用内置方法
pytest-yaml-yoyo 插件使用了强大的jinja2 模板引擎,所以我们在yaml文件中可以写很多python内置的语法了。
3.4.1 调用 python 内置方法
举个例子: 我定义了一个变量username的值是test123,但是我引用变量的时候只想取出前面四个字符串,于是可以用到引用变量语法
可以直接对变量用python的切片语法
test_fun1.yml
命令行执行用例
运行结果
3.4.2 字典对象取值
如果定义一个字典类型的变量,我们在取值的时候也可以根据key取值 如定义变量
user和email的取值用2种方式,通过
点属性
或者用字典取值方法[key]
test_fun2.yml完整示例
3.5 自定义函数功能
一些复杂的逻辑处理,需自己写代码去实现,于是可以自定义函数。
3.5.1 自定义函数
自定义函数的实现,需在conftest.py (pytest 框架内置的插件文件)文件中实现
实现基本原理是自己定义一个函数,然后注册到插件内置模块
my_builtins
。这样我们在用例中就能找到该函数方法了test_fun3.yml 用例中引用内置函数示例
3.5.2 函数传参数
在引用自定义函数的时候,也可以传变量
test_fun4.yml示例
函数还能引用自己在config 中定义的变量
3.5.3 函数返回的结果也能二次取值
如果一个函数返回list类型,我们在用例中也能取出其中的一个值
test_fun5.yml示例
list类型支持2种取值方式
${func_list().1}
或者${func_list()[1]}
3.5.4 内置函数的使用
目前暂时提供了3个内置函数,和1个内置对象
还提供了一个内置的fake 对象,可以生成随机手机号,随机身份证,姓名等数据
使用方法:
${fake.name()}
,fake.phone_number()
,fake.email()
等,具体查看Faker模块提供的方法https://www.cnblogs.com/yoyoketang/p/14869348.htmlcurrent_time() 获取当前时间, 使用示例
rand_value(target: list) 从返回的 list 结果随机取值, 有小伙伴提到的需求
rand_str(len_start=None, len_end=None) 生成随机字符串,默认32位
rand_str 使用方法: ${rand_str()} 得到32位字符串 ${rand_str(3)} 得到3位字符串 ${rand_str(3, 10)} 得到3-10位字符串
以上yaml,生成的json数据示例
3.5.5 fake 对象的使用
内置的 fake 对象 (注意是fake,不是faker, 因为faker 是模块名称,避免冲突) ,可以生成随机手机号,随机身份证,姓名等数据
生成的测试数据
其它更多方法参考Faker模块提供的方法https://www.cnblogs.com/yoyoketang/p/14869348.html
3.6 钩子功能
3.6.1 response 钩子功能
在发送请求的时候,我们希望在发送请求参数前,带上签名的值,或者返回的内容需要二次处理,解密后返回。 此功能我们可以用 hooks 钩子来实现 hooks 功能在v1.0.4版本上实现
requests 库只支持一个 response 的钩子,即在响应返回时可以捎带执行我们自定义的某些方法。 可以用于打印一些信息,做一些响应检查或想响应对象中添加额外的信息
以上是基于requests 库的钩子功能实现的基本方式
3.6.2 yaml 用例中添加response 钩子
在yaml 文件中添加response 钩子功能,跟上面代码方式差不多, 有2种方式
先看单个请求的response 钩子 test_hook1.yml
在 conftest.py 中注册钩子函数
由于上面用例只在第一个请求中使用了hooks功能,所以第二个请求的断言
- eq: [$.code, 0]
会失败3.6.3 钩子方法调用语法
func1, func2
,或者是一个list类型[func1, func2]my_builtins
模块response
, 可以重写response内容(如需要对返回结果解密),也可以不用重写3.6.4 config 全局钩子使用
在config 中配置全局hooks功能,格式如下
test_hook2.yml完整示例
全局配置hooks, 那么该用例下所有的请求都会带上hooks
3.6.5 请求预处理钩子
如果需要对请求参数预处理,我们还新增了一个request 请求钩子,可以获取到发送请求时的request参数
在conftest.py
在 yaml 文件中使用示例
在config 中设置全局hooks示例
由于request 变量是 pytest的一个内置fixture,此变量保留着,获取请求参数的函数使用
req
代替。 利用request hook功能可以实现请求参数的预处理,比如请求 body 签名和加密处理等需求。3.7 用例分层
当我们测试流程类的接口,需反复去调用同一个接口,就会想到复用API,在代码里面可以写成函数去调用。 那么在yaml 文件中,我们可以把单个API写到一个yaml 文件,测试用例去调用导入API。
我这里只分2层:API 层 和 Test case 用例层
3.7.1 API 层示例
API 层只做接口的描述,一般放到项目根目录api目录下
api/login.yaml 示例
如果有需要用到变量,比如登录用户名在不同用例中会用到不同的账号,那么可以使用变量
${username}
需注意的是,API 层不支持单独运行,因为它只是用例的一个部分,不能当成用例去执行,用例执行需使用test_*.yml
命名3.7.2 TestCase 层
用例层通过api 关键字导入需要的API,导入的路径是相对路径,需根据项目的根目录去导入。 比如我的项目结构是这样的
那么不管用例文件
test_*.yml
在哪个目录,都是以项目根目录去导入API 的yaml文件运行用例也是在项目根目录去执行 pytest 运行
3.7.3 关于变量
API 层可以引用变量,引用变量的值都是从用例目录的variables 加载的变量,目前只支持config 设置用例全局变量
我们可以理解为API是用例的一个步骤,是用例的一部分,导入过去相当于复制request 请求到用例步骤里面。
3.7.4 关于校验
在API 层可以写一些基础的校验,比如校验状态码,我们一般不在API层写业务逻辑校验。 比如登录的用例,期望结果可以是登录成功,也可以是登录失败,那么业务逻辑的校验,应该在用例层去校验
如果API 层和用例层都有validate 校验,最后会合并到一起校验。
3.8 写多个用例
一个yaml 文件中可以写多个用例,yaml 文件相当于py模块,每个用例相当于模块里面定义 pytest 的一个函数, 用例名称最好是test开头,如果不是test开头,也会帮你自动拼接成test开头的
3.8.1 实现原理
在 pytest 用例中,我们可以在一个模块写多个函数式的用例,每个用例test开头,如下
执行后会看到3个用例
根据以上 pytest 的基本运行原理,于是我们也可以在yaml文件中写出同等的效果
输入 pytest 运行 yaml 用例文件
可以看出执行效果是完全一样的
3.8.2 重新定义了yaml用例格式
为了框架的可扩展性,config 和 teststeps 都不是必须的了,当然以前的格式还是会兼容
用例部分支持2种格式,可以是一个键值对格式
也可以是一个list
如果一个用例有多个步骤需要执行,那么用例应该是一个list,会按顺序去执行
3.8.3 支持中文命名
用例的函数名称也可以使用中文命名了,这样更直观
原有的用例规则不变,只是
teststeps
不是必须的关键字,可以用其它的名称,也可以继续使用teststeps
(为了兼容大家的使用习惯)3.9 文件上传
v1.1.3版本上实现文件上传
本插件集成了 requests_toolbelt 插件处理
Content-Type: multipart/form-data
类型文件上传接口。3.9.1 文件上传multipart/form-data
用fiddler抓包,查看抓到的接口,以下这种接口就是multipart/form-data
Content-Disposition: form-data; title=”localUrl”
yoyoketang.png
—————————–22165374713946
Content-Disposition: form-data; name=”imgFile”; filename=”yoyoketang.png”
Content-Type: image/png
3.9.2 在yaml 文件中示例
在postman 中,可以直接选择一个文件上传,非常方便
我们在yaml中也一样,支持文件类的参数,需单独拿出来放到 files 字段里面。
test_upfile.yml 示例
文件abc.jpg 需放到项目根目录data下
files 里面需要传的具体字段,需根据接口文档定义的参数名称。
当然你把其它字符串字段一起放到files 里面也没问题
(本插件也是根据你是否在 request 中传了 files 字段来判断是不是需要上传文件)
3.10 sleep和skip、skipif 功能
环境要求
Python 大于等于3.8版本,(低于python3.8版本不支持)
Pytest 7.2.0 最新版
v1.1.4 发布新增3个关键字
pip 安装插件, 最新版本v1.1.4
3.10.1 sleep 功能示例
sleep 功能实现time.sleep() 等待时间,sleep参数可以是int类型和float 类型
sleep 也可以是一个变量,引用config设置的变量值
sleep 执行顺序按写的顺序执行,如果放到request 前,那就在请求前先执行,放到request后,在请求后执行
3.10.2 skip 跳过用例
pytest 实现跳过用例有2种方式
或者在用例里面跳过
本插件采用的第二种实现方式,在用例里面添加pytest.skip()
skip 关键字后仅支持一个参数,那就是跳过的原因。使用示例
运行用例可以看到
如果用例是多个步骤组成的,也可以在步骤中跳过
那么会按顺序执行,第一个步骤会执行,第二个步骤因为有skip,就跳过了
如果还有第三个步骤,那么一旦遇到skip ,整个用例就会结束,skip 跳过的是用例,而不是步骤!
3.10.3 skipif 满足条件跳过
skipif 后面参数是一个表达式,当表达式运行结果为真,那么就跳过用例
skipif 还可以在多个用例中使用,当前面接口返回数据a,判断a满足条件就跳过后面用例
skikif 后面的参数需是字符串表达式,通过eval()函数运行后得到结果,判断是否为真,为真的时候通过当前用例。
4.项目配置/报告/日志
4.1 日志功能
pytest 的日志分2个部分:
本插件默认情况下会记录运行日志保存在项目根目录logs下,以当前时间保存txt文本日志内容。 日志默认保存info级别。 console 控制台默认不输出日志
4.1.1 开启 console 控制台日志
控制台直接运行 pytest 是不会用日志输出的,因为默认仅输出 warning 以上的级别日志 有3种方式启动console日志
方法1:命令行带上
--log-cli-level
参数,设置日志级别方法2: pytest.ini 配置开启日志,并且设置日志级别
方法3: pytest -o方式重写(即覆盖ini文件中的log相关的命令行参数)
即可在控制台看到日志
4.1.2 自定义 console 控制台日志
日志的格式和时间格式也可以自定义设置
4.1.3 自定义保存日志文件
本插件默认情况下会记录运行日志保存在项目根目录logs下,以当前时间保存txt文本日志内容。 日志默认保存info级别。 如果你想改变这些默认的行为,自定义日志文件目录和名称,可以在pytest.ini 配置日志文件 (log_file 相关的结果是保存日志文件到本地)
4.1.4 命令行参数配置
log日志的配置也可以用命令行参数配置(pytest -h可以查看)
还可以使用
pytest -o
方式重写(即覆盖 ini 文件中的 log 相关的命令行参数)4.2 allure 报告
本插件是基于 pytest 框架开发的,所以 pytest 的插件都能使用 allure 报告功能在 v1.0.8 版本上实现
4.2.1 allure 环境准备
allure 是一个命令行工具,需要去github上下载最新版https://github.com/allure-framework/allure2/releases
allure 命令行工具是需要依赖jdk 环境,环境内容自己去搭建了
4.2.2 生成 allure 报告
在用例所在的目录执行命令,
--alluredir
是指定报告生成的目录打开allure 报告执行命令
4.2.3 查看报告
首页显示
4.3 全局 base_url
一个完整的url 地址由环境地址和接口地址拼接而成,环境地址是可变的,可以部署到测试环境,uat联调环境等不同的环境。 不管部署到哪个环境,接口的地址是不可变的,通常需要一个全局base_url 地址做到环境可切换。 pip 安装插件
base_url 全局配置功能在 v1.0.9 版本上实现
4.3.1 环境地址
在接口测试中,通常会把环境 base_url 地址独立出来 比如一个完整的请求
http://httpbin.org/get
那么可以分成环境地址http://httpbin.org
和 接口地址/get
在 yaml 用例中,可以把 base_url 单独拿出来放到 config 下
4.3.2 全局 base_url 配置
从项目的角度讲,测试项目接口的 base_url 都是一样的,所以我们只需全局设置一个就行了,不需要每个yaml 文件中重复去写。 于是可以在pytest.ini 里面配置全局base_url
那么yaml用例就不需要写 base_url 了,默认会引用pytest.ini的全局配置
yaml 用例1
yaml 用例2
除了可以在pytest.ini 配置base_url 参数,也可以通过命令行参数
--base-url
去设置4.3.3 复杂情况
当设置了全局base_url 后,有部分用例的环境地址不是同一个的时候,我们可以在yaml文件中config 配置 base_url 去覆盖全局配置环境地址。
或者请求 url 地址用绝对地址
4.3.4 使用优先级
环境地址优先级使用如下: 1.全局配置命令行参数
--base-url
优先级大于 pytest.ini 文件中的 base_url 配置。 2.yaml 文件 config 中的base_url 优先级大于全局配置 3.request 请求的url 如果是绝对地址,那么base_url 无效总的来说 : url 绝对地址 > config 中的base_url > pytest.ini 文件中的base_url > 命令行参数
--base-url
4.4 全局项目配置
当我们在测试环境写好自动化的代码,领导说你把代码部署到联调环境再测一测,这时候去改用例里面的配置是很痛苦的。 所以我们在设计自动化用例的时候,就先要想到多环境的配置与切换。
4.4.1 多环境配置
如果需用到多套环境 test/uat 等,那么应该在用例的根目录(pytest.ini 同级文件)创建一个config.py 文件 pip 安装插件
多套环境切换功能在 v1.0.10 版本上实现
按以上的配置格式,配置不同的环境,最后做一个环境名称和配置的映射关系,必须是 env 命名,格式如下
那么在执行用例的时候,可以选择执行test 环境还是uat 环境,有 2 种方式可以配置待执行的环境
方法一: 在pytest.ini 中配置
方法二: 执行 pytest 命令的时候设置
如果2个地方都有设置,那么优先级是:命令行参数
--env test
大于 pytest.ini 中配置env = test
.4.4.2 测试环境的 BASE_URL
在上一篇中讲到 pytest + yaml 框架 -11.全局 base_url 配置
这里我们新增了一个在config.py 中也可以配置全局的base_url (config.py 中的配置用大写命名 BASE_URL)
如果在 config.py 中配置全局的 BASE_URL ,那么也会生效。优先级会低于命令行和 pytest.ini 的配置
总的来说:url 绝对地址 > config 中的base_url > 命令行参数–base-url > pytest.ini 文件中的 base_url > config.py 的 BASE_URL
4.4.3 多个base_url 切换
有同学提到说,如果一个用例中有多个base_url 需要切换,该如何解决?
我们在配置项中BASE_URL 项是设置默认的全局base_url地址,如果有多个地址,我们还可以用其它的配置参数,比如
BLOG_URL
和DEMO_URL
上面的配置中,我们就配置了3个环境地址
在yaml 用例中,如果没有传base_url, 那么会用默认的
BASE_URL = 'http://192.168.1.1:8000'
使用示例
当一个接口中同时用到3个测试地址
BASE_URL
、BLOG_URL
、DEMO_URL
时,可以通过 env 变量取值,如:${env.BLOG_URL}
4.4.4 其它配置参数
如果配置中需要加其它配置参数
那么在用例中引用配置参数可以用
${env.配置参数}
取到配置中的值。4.5 mysql 数据库配置
如果用例中需要执行mysql 数据库,或者在断言的时候需要查询mysql 数据库。先在config.py 中完成配置
当完成了MYSQL 相关的五个配置,那么有个内置的函数可以使用
4.5.1 断言执行sql
使用示例
以上示例是断言的时候,执行sql,获取数据库的值
可以开启日志
查看运行日志
从返回的body 里面提取username 使用表达式
$.username
, 得到实际结果”test” ‘${query_sql(sql).username}’ 表达式会先调用query_sql(sql) 函数,引用前面设置的变量sql, 得到结果得到的结果是一个字典,字典对象可以继续取值,于是
'${query_sql(sql).username}'
就可以得到期望结果 “test”4.5.2 用例的参数也可以查询sql
如果用例的参数,需要从sql中取值,我们也可以先定义变量,在用例中引用query_sql(sql) 函数
extract 中也可以支持执行sql,得到提取结果
4.5.3 用例前置和后置执行sql
如果需要在用例的前置和后置中执行sql, 可以用到hook 机制,在请求前和请求后执行函数 参考前面这篇pytest + yaml 框架 -6.hooks 钩子功能实现
4.6 全局代理
在实际的工作中,有些系统的接口我们无法直接访问,需使用代理去访问,那么就需要在整个项目的用例中配置一个全局代理ip
环境要求
Python 大于等于3.8版本,(低于python3.8版本不支持)
Pytest 7.2.0 最新版
pip 安装插件, 最新版本v1.1.6,此功能在v1.1.6版本上实现
支持2种方式实现
1.在命令行执行的时候带上
--proxies-ip=代理ip:端口
2.可以在pytest.ini 添加全局配置
注意配置的ip和端口,前面的 http/https 前缀不需要
4.6.1 使用示例
test_pp.yaml 用例文件中不需要添加额外的参数
方式1:命令行运行
方式2:使用 pytest.ini 添加全局配置
5.反馈通知
5.1 钉钉机器人通知
当用例执行完成后,希望能给报告反馈,常见的报告反馈有:邮箱/钉钉群/飞书/企业微信 等。 pip 安装插件
钉钉机器人通知测试结果功能在v1.1.1版本实现
5.1.1 钉钉机器人设置
钉钉机器人的设置请参考官方API文档https://open.dingtalk.com/document/group/custom-robot-access
我们主要得到Webhook地址上面的access_token 值
自定义关键字,默认:测试报告,也可以自定义
加签 的值,可以不勾选,也可以勾选。
总的来说,需要记住3个地方:
5.1.2 config 中配置 DING_TALK 项
在config 中配置 DING_TALK, 只有 access_token 值是必须项, 如果配置了 DING_TALK ,那么就会自动启动发送钉钉机器人通知。 如果不启动钉钉机器人通知测试报告,那么把此项注掉即可。
在pytest.ini 中配置
DING_TALK 相关参数说明
运行用例后会自动在钉钉群发送通知
5.1.3 加签值配置
如果这里没有勾选 加签 值
那么只需要配置一个 access_token 即可
如果这里勾选 加签 值, 那么需同时配置 access_token 和 secret 值
5.1.3 设置@指定的人
奈特指定的人有3个配置可以选择
使用示例
于是就可以看到上图的效果,在内容后面带上
@张三
的样式5.1.4 设置 title 和 内容
title 的名称必须与自定义关键字名称保持一致
报告的 text 内容, 也就是我们看到的
text 的内容,默认是上面的这些,支持markdown 文档格式,如果你需要添加额外的内容,比如加上allure报告地址,那么可以用 text 字段追加内容
把上面的
https://www.cnblogs.com/yoyoketang/
换成你自己的allure报告地址即可于是看到以下的效果
总的来说,整个配置都是傻瓜式的,配置非常简单。
6.扩展功能
6.1 swagger.json 自动生成 yaml 接口用例
当项目中有很多个接口的时候,一个个去转成 yaml 文件的用例会很浪费时间,现在大部分格式的接口都有swagger.json 接口文档。 那么我们可以从swagger.json 中解析出接口,自动生成 yaml 格式的用例,就可以大大减少工作量。 此功能在 v1.1.5 版本上实现
环境要求 Python 大于等于3.8版本,(低于python3.8版本不支持) Pytest 7.2.0 最新版
pip 安装插件, 最新版本v1.1.5
6.1.1 使用示例
目前支持2中方式生成 yaml 用例。 1.如果有本地的 swagger.json 文件,可以放到项目根目录,自己写 a.py 文件 目录结构如下
a.py 文件调用插件中的接口即可
a.py 文件调用插件中的接口即可
6.1.2 yaml 用例自动生成
执行完成后会在当前项目目录按接口模块生成对应的yaml格式用例
yaml 文件格式示例
相关 功能参考全局 base_url 的设置文档https://www.cnblogs.com/yoyoketang/p/16970491.html
备注说明: 1.并不是所有的swagger.json格式都支持,目前我是按flask项目生成的swagger.json 格式来解析的,其它的未知,思路供学习和参考。 2.目前只实现基础功能,需写上面代码调用此功能,暂不支持命令行操作 3.目前仅仅是抓取接口和请求参数,自动生成用例结构 4.参数部分拿文档的默认值,还需自己去调试,写对应的测试数据 5.后续想法是根据参数的范围,按等价类,边界值去生成对应的用例 6.断言部分功能未实现,目前仅断言状态码为200
7.VIP 付费功能
付费用户可获取最新版本功能,和版本升级服务
7.1 录制功能自动转 yaml 用例
7.1.1 环境准备
录制功能环境没给大家预装,考虑大家 python 版本不太一样,可能有的人装不上。官方文档地址https://docs.mitmproxy.org/stable/ 1.先需要准备
mitmproxy
环境,最好是 python3.9 版本, 使用 pip 安装接口2.安装完成后在项目本地新建一个
recorde.py
,名称随便定义3.执行命令启动服务, 指定监听 8099 端口
启动后我们会看到浏览器打开抓包页面
4.电脑开启代理,设置对应端口
浏览器-设置-系统-打开您计算机的代理设置 开启代理-设置8099打开-并点保存 保存后就可以开始抓包了,电脑上发出去的请求都能抓到,比如浏览器打开你要测试的地址,或者通过python写的接口脚本, postman 上执行的接口都能抓到
5.自动抓包生成 yaml 用例 抓到接口会自动生成 yaml 格式用例,如下
7.1.2 常用的参数配置
RecoderHTTP
实例化时,可以设置以下几个参数1.默认情况下,只需传一个参数,抓取的环境地址,可以是一个,也可以是多个
也可以抓取多个环境地址
2.ignore_cookies 是设置是否忽略cookies抓取,默认False
设置为True, 录制的yaml 用例中不会带上cookies
3.
save_base_url
是否在 pytest.ini 保存全局base_url环境地址, 默认False. 默认情况下,每个yaml 用例中在config 添加base_url 环境地址,兼容抓取多个环境的情况 如果只需抓一个环境的地址,设置全局base_url地址,设置save_base_url=True
抓取用例时会自动创建 pytest.ini 文件
用例抓取完成后,重新打开一个终端窗口,输入 pytest 命令就能执行用例了
7.2 mock 功能
前面已经通过代理实现了抓包自动生成 yaml 用例的功能,通过代理也可以实现 mock 功能。 mock 有2种场景: 1.直接拦截发出去的请求,还未到达服务端,模拟自定义返回结果 2.发出去的请求,服务端有反回,拦截返回的结果,篡改返回内容,模拟自己需要的数据
7.2.1 拦截发出去的请求
先看第一种场景:直接拦截发出去的请求,还未到达服务端,模拟自定义返回结果
mt_mock.py 内容如下
启动服务
本机开启代理,设置8099端口。
浏览器访问
https://www.cnblogs.com/yoyoketang/
地址,就会看到模拟的返回结果7.2.2 拦截返回的结果,篡改返回内容
第二种场景:发出去的请求,服务端有反回,拦截返回的结果,篡改返回内容,模拟自己需要的数据
使用示例:访问
http://www.example.com/
本来返回的是html格式,我改下返回json格式7.3 mark 标记功能
pytest可以支持对用例自定义标记, 可以把用例按自己的需要归类标记,比如按用例优秀级,标记一些smoke冒烟测试用例。
7.3.1 pytest 标记基本使用
test_m.py 用例内容
执行的时候加-m 参数
7.3.2 yaml 用例中加 mark 标记
yaml 用例中支持2个地方加标记
需注意的是一个用例可以打多个标记,mark 关键字可以是一个字符串,如果是多个标记,可以用
mark: name1, name2
或mark: [name1, name2]
两种格式 test_m.ymlconfig 中加标记,对test_a1 和 test_a2 都会打上标记
test_n.yml
1.执行标记为 www 的用例
运行结果
2.执行标记为 aaa 的用例
运行结果
3.执行标记了www并且也标记aaa的用例
4.执行没有标记www的用例
5.执行标记了www或aaa的用例
7.4 mark 标记对用例运行时长断言
pytest 执行用例的时候,我们希望对用例的运行时间断言,当用例执行时长大于预期标记此用例失败。
@pytest.mark.runtime(1)
运行时长单位是秒 此插件已打包上传到pypi https://pypi.org/project/pytest-runtime-yoyo/环境准备
此功能在v1.3.1 版本上实现
7.4.1 代码中实现
基本示例 test_demo.py
运行结果
7.4.2 在 yaml 用例中实现
在yaml 中添加 runtime
也可以在config 中添加runtime 对整个yaml 中的用例标记
如果config 中和用例中都有runtime ,那么用例的runtime优先级>config 中的runtime
7.4.3 全局用例配置
对全部用例设置 runtime 标记,可以在
pytest.ini
中设置全局配置也可以在执行 pytest 命令的时候带上命令行参数
--runtime
优先级是: 命令行参数 > pytest.ini 配置 全局配置只针对yaml 中config,测试用例没标记 runtime 的用例生效。 如果yaml 中config,测试用例有标记 runtime,那么优先级是大于全局配置的。
7.5 export 提升全局变量,支持跨yaml文件用例传参
export 导出功能, config 和 case 中都能添加。 简单来说,就是test_a.yml 执行完成后,提取了变量x, 在后面的test_b.yml 和 test_c.yml 中可以直接引用变量x了。
7.5.1 extract 提取变量
在单个测试yaml 用例文件中,可以支持写多个用例,并且extract 提取的变量,在整个yaml文件中都可以直接引用。
test_ext3.yml
使用
pytest test_ext3.yml
命令运行用例7.5.2 export 提升全局变量
test_ext3.yml 用例中提取的email 变量作用范围仅在test_ext3.yml 中使用有效,无法跨yaml 文件引用。 如果想后面的用例,继续使用提取的email 变量, 需使用export 关键字,提升变量的级别为session会话级别,也就是真正的全局变量。
export
关键字可以写到config 也可以写到用例中,格式必须是list 类型。 test_extract/test_ext3.yml在接下来的test_ext4.yml 和其它用例可以直接引用
${export}
test_extract/test_ext4.yml前提条件是 test_ext3.yml 用例要先执行,pytest 在执行的时候按用例名称顺序执行, 可以放到test_extract 同一个文件夹下一起执行
执行后部分log日志
export 关键字也可以在用例中使用,跟config 中使用效果引用,如果2个地方都有,会自动合并
test_extract/test_ext3.yml
7.5.3 变量优先级
在整个用例中有 config 配置文件中设置的env 环境变量,export 导出的session 变量,yaml 文件中的config 模块变量,用例中的variables 局部变量。 整体优先级是:用例中的variables 局部变量 > extract 提取变量 > yaml 文件中的config 模块变量 > export 导出的session 变量 > 配置文件中设置的env 环境变量 test_extract/test_ext5.yml
pytest test_extract
执行用例可以看到 test_ext7 用例引用局部变量值
yoyo@qq.com
, test_ext8 引用export 导出的 session 会话变量值123@qq.com
7.6 支持飞书机器人通知
7.6.1 自定义飞书机器人
飞书机器人配置详细文档参考:https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN
第一步:邀请自定义机器人入群
进入你的目标群组,打开会话设置,找到群机器人,并点击添加机器人,选择自定义机器人加入群聊。
第二步: 设置机器人名称和描述 为你的机器人输入一个合适的名字和描述,也可以为机器人设置一个合适的头像,然后点击下一步。
第三步:复制 webhook 地址
webhook地址复制出来:
https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxx
hook/
后面的一串xxxxxxxxxxxxxxxxx
就是我们要的 token7.6.2 config 配置 FEI_SHU
在项目根目录(pytest.ini 同级文件)创建一个config.py 文件
在 pytest.ini 中配置运行环境
7.6.3 运行用例生成报告
通过pytest 命令行运行用例
运行完成后,会根据你配置的token内容,触发飞书通知
用例成功,背景显示绿色
用例失败,背景显示红色
7.7 企业微信机器人通知
7.7.1 获取企业微信机器人token
企业机器人相关接口可以看官方文档https://developer.work.weixin.qq.com/document/path/91770 创建群聊机器人
获取到webhook访问地址
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=*********************
key= 后面的这串就是我们要的token7.7.2 配置企业微信机器人通知
在运行环境配置中加一个WE_COM的配置即可
配置 WE_COM
在 pytest.ini 中配置运行环境
执行用例就会自动触发企业微信机器人
7.8 模板过滤器语法与自定义过滤器使用
针对有同学提到上个接口返回一个id值,下个接口引用变量的时候需要根据这个值做一些运算,比如在引用的结果加1. 本篇介绍下模板过滤器的相关使用.
7.8.1 jinja2 模板过滤器语法
什么是 jinja2 模板过滤器?
通过在 Jinja2 模板中嵌入变量,可以输出变量的值。但是,在很多情况下,不仅仅只是需要输出变量的值,还需要修改变量的显示,对变量进行格式化、运算等。 为了方便对变量进行处理,Jinja2 提供了过滤器,Jinja2 过滤器是一个函数,该函数对输入变量进行变换处理后,返回一个值作为 Jinja2 模板的输出。
在 yaml 用例文件中引用变量,使用 Jinja2 中过滤器有如下用法:
示例1:过滤器不带任何参数
例如:过滤器 upper 将输入变量 var 转换为大写,
${"hello" | upper }
的输出为 “HELLO”。示例2:过滤器带参数的情况
例如:过滤器 replace (source, target) 将输入变量 var 中的字符串 source 替换为字符串 target,
${"hello world" | replace ("hello", "yoyo") }
的输出为 “hello yoyo”。示例3:过滤器可以组合使用
过滤器可以组合使用,
${var | filterA | filterB}
的处理过程如下:例如:
${"abc" | upper | reverse }
的输出为 “CBA”。7.8.2 常用的过滤器
${ 'yoyo' | capitalize }
${ 'hello world' | title }
${ 'HELLO' | lower }
${ 'hello' | upper }
${ 'abc' | reverse }
${ 'my name %s, %d years.' | format('yoyo', 20) }
${ ['hello', 'world', 'yoyo'] | first}
${ ['hello', 'world', 'yoyo'] | last}
${ ['hello', 'world', 'yoyo'] | length}
${ [1, 2, 3] |sum }
${ [1, 3, 2] | sort }
{ [1, 3, 2] | sort(reverse = True) }
['hello', 'world', 'yoyo'] | join('_')
${ gender | default('male') }
${20 | add(1)}
上面的过滤器方法除了add是我自定义的一个内置方法,其它都是jinja2模板引擎自带的过滤器方法。
7.8.3 使用示例
在yaml 用例中使用过滤器语法 test_a.yml
使用pytest 运行用例
运行结果:
7.8.4 自定义过滤器
自定义过滤器语法跟自定义函数有点类似,也是在项目根路径下conftest.py 文件上注册过滤器
conftest.py
yaml 中用例使用 test_b.yml
运行结果
7.9 支持自定义函数提取返回结果
在 yaml 用例中提取返回结果,可以支持以下三种表达式
以上三种表达式可以满足 99% 的测试场景需求了,但是有些特殊的需求通过表达式无法取到,为了满足另外1%的需求,可以自定义函数取值。 此功能在v1.3.6版本实现
7.9.1 场景描述
有个小伙伴给我提了个需求:如果返回的结果中有某个值就断言,没有就不断言
示例:如下返回结果,当data中name的值为”yoyo”的时候,断言它的邮箱值”283340479@qq.com“,如果结果中没有name的值为”yoyo”就不断言
7.9.2 代码示例
先自定义函数取值,传一个 response (接口返回对象)
conftest.py 内容如下:
yaml 用例中内容, 校验地方可以引用函数
${fun_x(response)}
, response 参数是接口返回对象。 test_rep.yml执行用例
运行结果:
7.10 parameters参数化支持笛卡尔积
v1.3.8 版本对 parameters 参数化格式重新做了定义,支持笛卡尔积了。当然以前旧版本的格式还是继续兼容。
7.10.1 parameters 参数化
新版本对 parameters 参数化重新做了定义,简化了步骤,更加清晰简洁.
1.只有一个变量需要参数化的情况
test_p1.yml
运行结果
2.有2个变量需要参数化的情况,变量中间用逗号隔开(或者-) test_p2.yml
也可以实现横线隔开
运行结果
7.10.2 笛卡尔积
对2个变量同时参数化,生成笛卡尔积的情况 x 变量只有一个值,可以写成
x: "a"
, 也可以写成x: ["a"]
test_p3.ymlx 变量也可以有多个值 test_p4.yml
运行结果
7.10.3 模块级别和用例级别参数化
支持模块级别和用例级别参数化
用例级别参数化 test_p5.yml
运行结果
config 中 parameters 参数化,作用域是整个模块级别, test_p6.yml 文件示例
运行结果
7.11 仅收集用例失败错误信息和log日志
有小伙伴提到能不能只收集用例失败的情况下日志和错误信息,每个用例都收集日志内容太多了,没法直观的看错误的用例信息。 v1.3.9 版本实现此功能,在原有的功能上新增一个log日志文件,仅收集用例错误的日志。
7.11.1 log 日志收集
用例执行完会默认生成2个日志文件
使用示例
用例执行后根据当前时间生成一个20230707_201045_error.log 日志文件
根据用例节点
a1/test_a2.yml::test_2
详细记录用例报错的内容和用例运行的日志.7.12 allure报告自定义内容
v1.4.0 版本支持allure报告自定义内容
7.12.1 用例添加 allure 描述
用例中可以通过dynamic 添加以下内容
在test_a.yml 用例中示例
命令行执行用例,并启动allure服务查看报告
7.12.2 用例有多个步骤,添加step描述
在test_b.yml 用例中有多个步骤:
test_b.yml 示例
7.12.3 config 中定义公共allure
同一个 yaml 文件中,有多个用例都需加相同的 allure 内容,可以在 config 中定义公共的allure内容 test_c.yml 内容
7.13 redis 配置
v1.4.1 新增 redis 数据库配置
7.13.1 redis 基本操作
环境准备
python 操作redis 基本代码
7.13.2 yaml 用例中操作redis
config 配置中配置 REDIS
yaml 用例中使用 ‘redis’对象,调用对应方法如:’redis.get(‘x’)’
7.14 支持 websocket 协议
v1.4.2 版本支持 websocket 协议
7.14.1 python 操作websocket 协议
环境准备
基本代码示例
运行结果
7.14.2 yaml 中 webscoket 用例实现
ws关键字相当于
create_connection(url, timeout=10)
创建连接 send 关键字相当于ws.send('hello')
发送文本消息`运行结果
websocket 一次连接可以发送多个请求,所以可以在一个用例中有多个send请求
7.14.3 多个连接地址测试
一个yaml 文件中可以有多个连接
多个url地址公共环境地址 base_url 也可以写的config中
执行结果
8.版本变更记录
v1.0.0 发布的第一个版本(已删除)
v1.0.1 发布时间 2022.11.23 可以安装的第一个版本
v1.0.2 发布时间 2022.11.24
详细功能参阅 extract 关键字文档
v1.0.3 发布时间 2022.11.28
详细功能参阅 parameters 参数化 关键字文档
v1.0.4 发布时间 2022.11.30
hooks 钩子功能实现
详细功能参阅 hooks 钩子 关键字文档
v1.0.5 发布时间 2022.12.05
用例分层机制
v1.0.6 发布时间 2022.12.06
一个yaml 中写多个用例,用例步骤可以不是list 类型
v1.0.7 发布时间 2022.12.08
新增日志
v1.0.8 发布时间 2022.12.09
结合 allure 生成报告
v1.0.9 发布时间 2022.12.09
全局 base_url 配置
base_url
配置--base-url
参数v1.1.0 发布时间 2022.12.13
多环境配置切换
env
配置, 命令行新增--env
参数v1.1.1 发布时间 2022.12.14
钉钉机器人通知测试结果
v1.1.2 发布时间 2022.12.16
内置方法提供
v1.1.3 发布时间 2022.12.17
v1.1.4 发布时间 2023.2.13
新增3个关键字
v1.1.5 发布时间 2023.2.16
支持 2 中方式生成 yaml 用例
v1.1.6 发布时间 2023.2.17
支持2种方式实现
--proxies-ip=代理ip:端口
--proxies-ip=代理ip:端口
v1.1.8 发布时间 2023.3.17
int 转 str 类型
v1.1.9 发布时间 2023-03-21
做了以下优化
v1.2.0 发布时间 2023-05-08
优化以下问题
v1.2.1 发布时间 2023-05-20
优化以下问题
txt/csv/json/yaml
${fun("hello ${key}")}
to_json()
函数,字典转 jsonv1.2.3 版本 1.解决用例中,hooks单独写request 报错问题 —已发布的1.2.0解决 2.内置to_json() 函数,字典转 json 4.export 导出功能, config 和 case 中都能添加
v1.2.4 版本 1.新增飞书机器人报告 2.统计报告添加skip 统计
v1.2.5 版本 1.函数的参数可以引用变量了,如: ${fun(“hello ${key}”)} 2.兼容python3.8, python3.9, python3.10版本
v1.2.6 1.解决与 pytest-base-url 插件不兼容问题 2.解决len_eq 断言 list 长度问题 3.模板过滤器 filter 支持
v1.2.7 1.解决请求钩子函数中传环境配置问题 2.新增内置fixture environ 返回当前运行环境对象
v1.2.8 1.解决用例全部 skip 报错问题 2.解决文件上传参数全部传 files 不生效问题 3.数据库配置支持 DB_INFO 参数传字典类型 4.jmespath 表达式支持length 等函数的提取
v1.2.9 发布
1.优化参数化路径读取,以项目根路径拼接路径 2.优化len_eq 3.变量取值优化
v1.3.0
1.mark 标记实现,config 和用例中都能加 mark
v1.3.1
1.用例超时功能需安装 pytest-runtime-yoyo 插件 2.
mark: runtime(1)
标记用例运行超时,单位是秒v1.3.2 1.企业微信机器人通知
v1.3.3 1.添加
--start-project
创建项目demov1.3.4 1.录制功能
v1.3.5 1.录制功能,支持 multipart/form-data 2.优化录制 yaml 格式用例
v1.3.6 1.export 支持局部变量提升 2.validate 和 extract 支持自定义函数提取
v1.3.7 1.parameters 参数化支持模块级别
v1.3.8 1.parameters 参数化格式重新定义,支持笛卡尔积
v1.3.9 1.log 日志新增只收集用例失败日志
v1.4.0 allure 报告动态添加
v1.4.1 支持redis 配置 支持配置多数据库
v1.4.2 支持 websocket 协议
9 联系我们
作者-上海悠悠 微信/QQ交流:283340479 blog地址 https://www.cnblogs.com/yoyoketang/
完整视频教程地址https://study.163.com/course/courseMain.htm?courseId=1213419817&share=2&shareId=480000002230338 (视频收费:包含 pytest + yaml 框架开发教学和使用教学, 买课程的学员可以用新版本更多强大功能,咨询wx:283340479)