pytest + yaml 框架 -30.jsonpath 表达式提取接口返回结果
前言
pytest-yaml-yoyo 插件可以支持3种表达式提取接口返回结果。本篇详细介绍jsonpath 表达式提取json格式的返回结果。
(备注:从v1.2.4 以后新版本不再公开,新功能内部 VIP 学员可以使用,公开版本仅解决bug, 不提供新功能了。)
jsonpath 表达式基础语法
关于jsonpath的入门基础可以查看前面这篇https://www.cnblogs.com/yoyoketang/p/13216829.html
相关语法可以参考下表
JSONPath | 描述 |
---|---|
$ | 跟节点 |
@ | 现行节点 |
. or [] | 取子节点 |
.. | 相对节点 就是不管位置,选择所有符合条件的条件 |
* | 匹配所有元素节点 |
[] | 迭代器标示(可以在里面做简单的迭代操作,如数组下标,根据内容选值等) |
[,] | 支持迭代器中做多选 |
?() | 支持过滤操作 |
() | 支持表达式计算 |
使用示例, 接口返回如下数据。
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
jsonpath 取值表达式
JSONPath 表达式 | 取值结果 |
---|---|
$.store.book[*].author |
提取book里面全部author: ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien'] |
$..author |
提取全部author :['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien'] |
$.store.* |
store下的全部内容, 包含book和bicycle |
$.store..price |
store 下的全部price: [8.95, 12.99, 8.99, 22.99, 19.95] |
$..book[2] |
下标获取book里第3个:[{'category': 'fiction', 'author': 'Herman Melville'...}] |
$..book[(@.length-1)] |
下标获取最后一个:[{'category': 'fiction', 'author': 'J. R. R. Tolkien'...}] |
$..book[-1:] |
切片获取最后一个:[{'category': 'fiction', 'author': 'J. R. R. Tolkien'...}] |
$..book[0,1] |
获取第1和第2个:[{'category': 'reference'...}, {'category': 'fiction',...}] |
$..book[:2] |
切片获取前2个:[{'category': 'reference'...}, {'category': 'fiction',...}] |
$..book[?(@.isbn)] |
获取book下用isbn 属性的内容:[{'category': 'fiction'... 'isbn': '0-553-21311-3',}, {'category': 'fiction'... 'isbn': '0-395-19395-8'...}] |
$..book[?(@.price<10)] |
过滤器筛选price小于10:[{'category': 'reference'...'price': 8.95}, {'category': 'fiction'...rice': 8.99}] |
$..* |
获取全部 |
$.store.! |
获取store下的key: ['book', 'bicycle'] |
$.store.book[0].title |
获取store 下第一个book的title属性:['Sayings of the Century'] |
$.store.book[(@.length-1)].title |
获取store 下最后一个book的title属性:['The Lord of the Rings'] |
$.store.book[?(@.price < 10)].title |
获取store 下price小于10的title属性: ['Sayings of the Century', 'Moby Dick'] |
(需注意的是python的jsonpath 并不支持函数的使用,如:$..book.length()
)
?()过滤器运算符
过滤器是用于筛选数组的逻辑表达式。一个典型的过滤器将是 [?(@.age > 18)]
,其中@表示正在处理的当前项目。
可以使用逻辑运算符&& 和 ||
创建更复杂的过滤器。 字符串文字必须用单引号或双引号括起来 ([?(@.name == 'yoyo')]
或者 [?(@.name== "yoyo")])
.
操作符 | 描述 |
---|---|
== |
left等于right(注意1不等于'1') |
!= |
不等于 |
< |
小于 |
<= |
小于等于 |
> |
大于 |
>= |
大于等于 |
=~ |
匹配正则表达式[?(@.name =~ /foo.*?/i)] |
in | 左边存在于右边 [?(@.size in ['S', 'M'])] |
nin | 左边不存在于右边 |
size | (数组或字符串)长度 |
empty | (数组或字符串)为空 |
?()过滤表达式的使用
?()过滤表达式。 表达式必须求值为一个布尔值,表达式一般结合@获取当前节点来过滤
import jsonpath
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
s = {
"code": 0,
"msg": "success!",
"data": [{
"id": 154,
"create_time": "2021-01-20 22:38:16",
"update_time": "2021-01-20 22:38:16",
"goodsname": "《selenium入门到精通到放弃》",
"goodscode": "sp_210001",
"merchantid": "",
"merchantname": "",
"goodsprice": 20.0,
"stock": 0,
"goodsgroupid": 0,
"goodsstatus": 1
}, {
"id": 1,
"create_time": "2021-01-17 15:14:25",
"update_time": "2021-01-20 22:21:51",
"goodsname": "《jmeter 入门到精通》",
"goodscode": "sp_100049",
"merchantid": "10001",
"merchantname": "悠悠学堂",
"goodsprice": 100.0,
"stock": 1,
"goodsgroupid": 1,
"goodsstatus": 1
}, {
"id": 150,
"create_time": "2021-01-19 23:43:47",
"update_time": "2021-01-19 23:43:47",
"goodsname": "《cypress 入门到精通》",
"goodscode": "sp_10002232",
"merchantid": "1000122",
"merchantname": "悠悠学堂",
"goodsprice": 49.9,
"stock": 100,
"goodsgroupid": 0,
"goodsstatus": 1
}, {
"id": 148,
"create_time": "2021-01-19 23:42:20",
"update_time": "2021-01-19 23:42:20",
"goodsname": "《appium 入门到精通》",
"goodscode": "sp_426001",
"merchantid": "42601",
"merchantname": "悠悠学堂",
"goodsprice": 99.9,
"stock": 100,
"goodsgroupid": 0,
"goodsstatus": 1
}, {
"id": 147,
"create_time": "2021-01-19 22:22:41",
"update_time": "2021-01-19 22:22:41",
"goodsname": "《pytest 入门到精通》",
"goodscode": "sp_100119",
"merchantid": "",
"merchantname": "",
"goodsprice": 10.0,
"stock": 0,
"goodsgroupid": 0,
"goodsstatus": 1
}]
}
1.找出商品价格大于20的全部商品信息
# 价格大于20的
data1 = jsonpath.jsonpath(s, '$.data[?(@.goodsprice > 20)]')
print(data1)
# 价格大于20的goodscode
goodscodes = jsonpath.jsonpath(s, '$.data[?(@.goodsprice > 20)].goodscode')
print(goodscodes) # ['sp_100049', 'sp_10002232', 'sp_426001']
# 价格大于20的goodsname
goodsnames = jsonpath.jsonpath(s, '$.data[?(@.goodsprice > 20)].goodsname')
print(goodsnames) # ['《jmeter 入门到精通》', '《cypress 入门到精通》', '《appium 入门到精通》']
2.取出 'goodscode': 'sp_100049' 对应的 goodsname
# 取出 'goodscode': 'sp_100049' 对应的 goodsname
name2 = jsonpath.jsonpath(s, '$.data[?(@.goodscode == "sp_100049" )].goodsname')
print(name2) # ['《jmeter 入门到精通》']
3.取出 'goodscode': 'sp_100049' 和 'goodscode': 'sp_100119' 对应的 goodsname
# in 包含在内 nin不存在
name3 = jsonpath.jsonpath(s, '$.data[?(@.goodscode in ["sp_100049", "sp_100119"])].goodsname')
print(name3) # ['《jmeter 入门到精通》', '《pytest 入门到精通》']
在 yaml 用例中使用 jsonpath 表达式提取示例
/api/test/demo 接口返回内容如下
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
{
"code": 0,
"msg": "成功success!",
"data": [
{
"age": 20,
"create_time": "2019-09-15",
"id": 1,
"mail": "283340479@qq.com",
"name": "yoyo",
"sex": "M"
},
{
"age": 21,
"create_time": "2019-09-16",
"id": 2,
"mail": "123445@qq.com",
"name": "yoyo111",
"sex": "M"
}
]
}
test_jsonpath.yml 测试用例文件内容
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
test_demo:
name: jsonpath取值示范
request:
url: http://127.0.0.1:8000/api/test/demo
method: GET
validate:
- eq: ['$.code', 0]
- eq: ['$.msg', 成功success!]
- eq: ['$..name', ["yoyo", "yoyo111"]]
- eq: ['$.data[0].name', yoyo]
- eq: ['$.data[(@.length-1)].name', yoyo111]
- eq: ['$.data[?(@.age > 20)].name', yoyo111]
- eq: ['$.data[?(@.name == "yoyo")].mail', 283340479@qq.com]
- eq: ['$.data[?(@.name in ["yoyo", "admin"])].mail', 283340479@qq.com]
- len_eq: ['$.data[?(@.age > 10)]', 2]
- len_eq: ['$..name]', 2]
运行日志:
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [0, 0]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [成功success!, 成功success!]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [['yoyo', 'yoyo111'], ['yoyo', 'yoyo111']]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [yoyo, yoyo]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [yoyo111, yoyo111]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [yoyo111, yoyo111]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [283340479@qq.com, 283340479@qq.com]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> eq: [283340479@qq.com, 283340479@qq.com]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> len_eq: [[{'age': 20, 'create_time': '2019-09-15', 'id': 1, 'mail': '2
83340479@qq.com', 'name': 'yoyo', 'sex': 'M'}, {'age': 21, 'create_time': '2019-09-16', 'id': 2, 'mail': '123445@qq.co
m', 'name': 'yoyo111', 'sex': 'M'}], 2]
2023-05-26 09:31:33 [INFO]: validate 校验结果-> len_eq: [['yoyo', 'yoyo111'], 2]
网易云完整视频课程https://study.163.com/course/courseMain.htm?courseId=1213419817&share=2&shareId=480000002230338
报名咨询wx:283340479 (已报名的同学学习过程中有问题,都可以协助解决)