同步操作将从 yoyo/pytest-yaml-yoyo 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
基于 httprunner 框架的用例结构,我自己开发了一个pytest + yaml 的框架,那么是不是重复造轮子呢? 不可否认 httprunner 框架设计非常优秀,但是也有缺点,httprunner3.x的版本虽然也是基于pytest框架设计,结合yaml执行用例,但是会生成一个py文件去执行。 在辅助函数的引用也很局限,只能获取函数的返回值,不能在yaml中对返回值重新二次取值。 那么我的这个框架,就是为了解决这些痛点。。。。
本插件可以实现以下优势:
作者-上海悠悠 微信/QQ交流:283340479 blog地址 https://www.cnblogs.com/yoyoketang/
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 生成报告
最近环境体验
pip 安装插件
pip install pytest-yaml-yoyo
yaml 用例编写规则,跟pytest识别默认规则一样,必须是test 开头的,以`.yml` 结尾的文件才会被识别
新建一个`test_hello.yml`文件
config: name: yy teststeps: - name: demo print: hello world
用例整体结构延续了 httprunner 框架的用例结果,主要是为了大家快速上手,减少新的规则学习
从上面的运行可以看出,request 不是必须的,我们可以直接调用python内置函数print 去打印一些内容了。
以`http://www.example.com/` get 请求示例 test_get_demo.yml
config: name: get teststeps: - name: get request: method: GET url: http://httpbin.org/get validate: - eq: [status_code, 200]
命令行输入 pytest 后直接运行
>pytest ======================= test session starts ======================= platform win32 -- Python 3.8.5, pytest-7.2.0, pluggy-1.0.0 rootdir: D:\demo\yaml_yoyo plugins: yaml-yoyo-1.0.1 collected 2 items test_get_demo.yml . [ 50%] test_hello.yml . [100%] ======================== 2 passed in 0.49s ========================
test_post_demo.yml
config: name: post示例 teststeps: - name: post request: method: POST url: http://httpbin.org/post json: username: test password: "123456" validate: - eq: [status_code, 200] - eq: [headers.Server, gunicorn/19.9.0] - eq: [$..username, test] - eq: [body.json.username, test]
比如返回的response内容
HTTP/1.1 200 OK Date: Wed, 23 Nov 2022 06:26:25 GMT Content-Type: application/json Content-Length: 483 Connection: keep-alive Server: gunicorn/19.9.0 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true { "args": {}, "data": "{\r\n \"username\": \"test\",\r\n \"password\": \"123456\"\r\n}", "files": {}, "form": {}, "headers": { "Content-Length": "55", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "Fiddler", "X-Amzn-Trace-Id": "Root=1-637dbd11-7d9943ba1fb93a9331f6cf8d" }, "json": { "password": "123456", "username": "test" }, "origin": "198.187.30.113", "url": "http://httpbin.org/post" }
校验方式延续了httprunner的校验语法,可以支持response取值对象:status_code, url, ok, headers, cookies, text, json, encoding 其中返回的是json格式,那么可以支持
如果返回的不是json格式,那么可以用正则取值
变量的声明,只支持在 config 声明整个yml文件的全局变量(不支持单个step的变量,减少学习成本) 在 httprunner 里面变量引用语法是 $user, 引用函数是`${function()}` 我这里统一改成了一个语法变量引用 ${var} 和 引用函数`${function()}` (表面上没多大变量,实际上功能强大了很多,使用了强大的 jinja2 模板引擎)
config: name: post示例 variables: username: test password: "123456" teststeps: - name: post request: method: POST url: http://httpbin.org/post json: username: ${username} password: ${password} validate: - eq: [status_code, 200] - eq: [headers.Server, gunicorn/19.9.0] - eq: [$..username, test] - eq: [body.json.username, test]
在自动化用例中,我们经常会看到有人提问,上一个接口的返回的结果,如何取出来给到下个接口的入参。 我们用 extract 关键字提取接口的返回结果(需要更新v1.0.2版本)。
举个例子 用个post请求`http://httpbin.org/post`
POST http://httpbin.org/post HTTP/1.1 User-Agent: Fiddler Host: httpbin.org Content-Length: 0 HTTP/1.1 200 OK Date: Thu, 24 Nov 2022 06:18:03 GMT Content-Type: application/json Content-Length: 320 Connection: keep-alive Server: gunicorn/19.9.0 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Content-Length": "0", "Host": "httpbin.org", "User-Agent": "Fiddler", "X-Amzn-Trace-Id": "Root=1-637f0c9a-23b419f4180f6b843ba941af" }, "json": null, "origin": "66.112.216.24", "url": "http://httpbin.org/post" }
比如我需要提取返回接口里面的url参数,那么我们用extract 关键字
test_demo.yml 文件示例
config: name: post示例 teststeps: - name: post request: method: POST url: http://httpbin.org/post json: username: test password: "123456" extract: url: body.url validate: - eq: [status_code, 200] - eq: [headers.Server, gunicorn/19.9.0] - eq: [$..username, test] - eq: [body.json.username, test]
上一个接口提取到了url 变量,接下来在下个接口中引用`${url}`
config: name: post示例 teststeps: - name: post request: method: POST url: http://httpbin.org/post json: username: test password: "123456" extract: url: body.url validate: - eq: [status_code, 200] - eq: [headers.Server, gunicorn/19.9.0] - eq: [$..username, test] - eq: [body.json.username, test] - name: post request: method: GET url: http://httpbin.org/get headers: url: ${url} validate: - eq: [status_code, 200]
于是看到请求报文中引用成功
GET http://httpbin.org/get HTTP/1.1 Host: httpbin.org User-Agent: python-requests/2.28.1 Accept-Encoding: gzip, deflate, br Accept: */* Connection: keep-alive url: http://httpbin.org/post
我们在前面提到不能在yaml中对返回值重新二次取值。, 这也是一些同学提到的问题,对于提取的结果,我想继续取值,比如他是一个字符串,在python中可以用切片取值 那么,在 yaml 中如何实现?
我重新设计的这个框架中,就可以支持python语法,直接用切片取值
headers: url: ${url[:4]}
当我们测试流程类的接口,需反复去调用同一个接口,就会想到复用API,在代码里面可以写成函数去调用。 那么在yaml 文件中,我们可以把单个API写到一个yaml 文件,测试用例去调用导入API。
我这里只分2层:API 层 和 Test case 用例层
API 层只做接口的描述,一般放到项目根目录api目录下
api/login.yaml 示例
name: post request: method: POST url: http://httpbin.org/post json: username: ${username} password: "123456" validate: - eq: [status_code, 200]
如果有需要用到变量,比如登录用户名在不同用例中会用到不同的账号,那么可以使用变量 ${username} 需注意的是,API 层不支持单独运行,因为它只是用例的一个部分,不能当成用例去执行,用例执行需使用 test_*.yml 命名
用例层通过api 关键字导入需要的API,导入的路径是相对路径,需根据项目的根目录去导入。 比如我的项目结构是这样的
├─api └─ login.yml ├─testcase └─ test_login.yml └─conftest.py └─pytest.ini
那么不管用例文件`test_*.yml`在哪个目录,都是以项目根目录去导入API 的yaml文件
config: name: login case base_url: http://127.0.0.1:8000 variables: username: "test123" password: "123456" teststeps: - name: step login1 api: api/login.yml extract: url: body.url validate: - eq: [status_code, 200] - eq: [ok, true] - name: step login2 api: api/login.yml
运行用例也是在项目根目录去执行 pytest 运行
pytest testcase
一个yaml 文件中可以写多个用例,每个用例相当于 pytest 的一个函数, 用例名称最好是test开头,如果不是test开头,也会自动拼接成test开头的
示例
test1: name: 用例1 print: hello 11111 test2: name: 用例2 print: hello 22222 test3: name: 用例3 print: hello 3333
为了框架的可扩展性,config 和 teststeps 都不是必须的了,当然以前的格式还是会兼容
config: name: demo teststeps: - name: GET请求示例 request: method: GET url: http://httpbin.org/get validate: - eq: [status_code, 200] test1: name: 用例1 print: hello 11111 test2: name: 用例2 print: hello 22222
用例部分支持2种格式,可以是一个键值对格式
test1: name: 用例1 print: hello 11111
也可以是一个list
test1: - name: 用例1 print: hello 11111
如果用多个步骤步骤需要执行,那么用例应该是一个list,会按顺序去执行
config: name: demo test1: name: 用例1 print: hello 11111 test2: - name: get request: method: GET url: http://httpbin.org/get validate: - eq: [status_code, 200] - name: post request: method: POST url: http://httpbin.org/post json: username: test password: "123456" validate: - eq: [status_code, 200]
pytest 的日志分2个部分:
本插件默认情况下会记录运行日志保存在项目根目录logs下,以当前时间保存txt文本日志内容。 日志默认保存info级别。 console 控制台默认不输出日志
开启 console 控制台日志
控制台直接运行 pytest 是不会用日志输出的,因为默认仅输出 warning 以上的级别日志 有3种方式启动 console 日志
方法1:命令行带上`--log-cli-level`参数,设置日志级别
>pytest --log-cli-level=info
方法2: pytest.ini 配置开启日志,并且设置日志级别
[pytest] log_cli = true log_cli_level = info
方法3: pytest -o方式重写(即覆盖ini文件中的log相关的命令行参数)
pytest -o log_cli=true -o log_cli_level=INFO
即可在控制台看到日志
-------------------------------------------- live log call -------------------------------------------- 2022-12-08 08:30:34 [INFO]: 执行文件-> test_demo.yml 2022-12-08 08:30:34 [INFO]: base_url-> None 2022-12-08 08:30:34 [INFO]: variables-> {} 2022-12-08 08:30:34 [INFO]: 运行 teststeps 2022-12-08 08:30:34 [INFO]: -------- request info ---------- POST http://httpbin.org/post { "method": "POST", "url": "http://httpbin.org/post", "json": { "username": "test", "password": "123456" } } 2022-12-08 08:30:35 [INFO]: ------ response info 200 OK 0.495961s------
自定义 console 控制台日志
日志的格式和时间格式也可以自定义设置
[pytest] log_cli = true log_cli_level = info log_cli_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s log_cli_date_format = %Y-%m-%d %H:%M:%S
自定义保存日志文件
本插件默认情况下会记录运行日志保存在项目根目录logs下,以当前时间保存txt文本日志内容。 日志默认保存info级别。
如果你想改变这些默认的行为,自定义日志文件目录和名称,可以在pytest.ini 配置日志文件 (log_file 相关的结果是保存日志文件到本地)
[pytest] log_cli = true log_cli_level = info log_cli_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s log_cli_date_format = %Y-%m-%d %H:%M:%S log_file = ./yoyo.log log_file_level = debug log_file_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s log_file_date_format = %Y-%m-%d %H:%M:%S
命令行参数配置
log日志的配置也可以用命令行参数配置(pytest -h可以查看)
--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.
还可以使用 pytest -o 方式重写(即覆盖 ini 文件中的 log 相关的命令行参数)
pytest pytest test_log.py -o log_cli=true -o log_cli_level=INFO
本插件是基于pytest框架开发的,所以pytest 的插件都能使用,生成报告可以用到 allure 报告 allure 报告功能在 v1.0.8 版本上实现
allure 命令行工具
生成 allure 报告
在用例所在的目录执行命令, --alluredir 是指定报告生成的目录
pytest --alluredir ./report
打开allure 报告执行命令
allure serve ./report
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。