使用 JsonPath 完成接口自动化测试中参数关联和数据验证(Python语言)
背景:
- 接口自动化测试实现简单、成本较低、收益较高,越来越受到企业重视
- restful风格的api设计大行其道
- json成为主流的轻量级数据交换格式
痛点:
- 接口关联
- 也称为关联参数。在应用业务接口中,完成一个业务功能时,有时候一个接口可能不满足业务的整个流程逻辑,需要多个接口配合使用,简单的案例如:B接口的成功调用依赖于A接口,需要在A接口的响应数据(response)中拿到需要的字段,在调用B接口的时候,传递给B接口作为B接口请求参数,拿到后续响应的响应数据。
- 接口关联通常可以使用正则表达式去提取需要的数据,但对于json这种简洁、清晰层次结构、轻量级的数据交互格式,使用正则未免有点杀鸡用牛刀的感觉(是的,因为我不擅长写正则表达式),我们需要更加简单、直接的提取json数据的方式。
- 数据验证
- 这里的数据验证指的是对响应结果进行数据的校验
- 接口自动化测试中,对于简单的响应结果(json),可以直接和期望结果进行比对,判断是否完全相等即可。如
json {"status":1,"msg":"登录成功"} - 对于格式较复杂,尤其部分数据存在不确定性、会根据实际情况变化的响应结果,简单的判断是否完全相等(断言)通常会失败。如:
json {"status":1,"code":"10001","data":[{"id":1,"investId":"1","createTime":"2018-04-27 12:24:01","terms":"1","unfinishedInterest":"1.0","unfinishedPrincipal":"0","repaymentDate":"2018-05-27 12:24:01","actualRepaymentDate":null,"status":"0"},{"id":2,"investId":"1","createTime":"2018-04-27 12:24:01","terms":"2","unfinishedInterest":"1.0","unfinishedPrincipal":"0","repaymentDate":"2018-06-27 12:24:01","actualRepaymentDate":null,"status":"0"},{"id":3,"investId":"1","createTime":"2018-04-27 12:24:01","terms":"3","unfinishedInterest":"1.0","unfinishedPrincipal":"100.00","repaymentDate":"2018-07-27 12:24:01","actualRepaymentDate":null,"status":"0"}],"msg":"获取信息成功"}上面的json结构嵌套了很多信息,完整的匹配几乎不可能成功。比如其中的createTime信息,根据执行接口测试用例的时间每次都不一样。同时这个时间是响应结果中较为次要的信息,在进行接口自动化测试时,是可以选择被忽略的。 - 我们需要某种简单的方法,能够从json中提取出我们真正关注的信息(通常也被称为关键信息)。如提取出status的值为1,data数组中每个对象的investId都为1,data中第三个对象的unfinishedPrincipal值为100.00,只要这三个关键信息校验通过,我们就认为响应结果没有问题。
解决方案
JsonPath可以完美解决上面的痛点。通过JsonPath可以从多层嵌套的Json中解析出所需要的值。
JsonPath
- JsonPath参照XPath解析xml的方式来解析Json
- JsonPath用符号$表示最外层对象,类似于Xpath中的根元素
- JsonPath可以通过点语法来检索数据,如:
shell $.store.book[0].title - 也可以使用中括号[]的形式,如
shell $['store']['book'][0]['title']
运算符(Operators)
| 运算符 | 说明 |
|---|---|
| $ | 根元素 |
| @ | 当前元素 |
| * | 通配符,可以表示任何元素 |
| .. | 递归搜索 |
| . | 子节点(元素) |
| ['' (, '')] | 一个或者多个子节点 |
| [ (, )] | 一个或者多个数组下标 |
| [start:end] | 数组片段,区间为[start,end) |
| [?()] | 过滤器表达式,其中表达式结果必须是boolean类型,如可以是比较表达式或者逻辑表达式 |
JsonPath案例
json
{"lemon":{"teachers":[{"id":"101","name":"华华","addr":"湖南长沙","age":25},{"id":"102","name":"韬哥","age":28},{"id":"103","name":"Happy","addr":"广东深圳","age":16},{"id":"104","name":"歪歪","addr":"广东广州","age":29}],"salesmans":[{"id":"105","name":"毛毛","age":17},{"id":"106","name":"大树","age":27}]},"avg":25}
JsonPath例子及说明
| JsonPath | 路径说明 |
|---|---|
| $.lemon.teachers[*].name | 获取所有老师的的名称 |
| $..name | 获取所有人的名称 |
| $.lemon.* | 所有的老师和销售 |
| $.lemon..age | 所有人的年龄 |
| $..age | 所有人的年龄 |
| $.lemon.teachers[*].age | 所有老师的年龄 |
| $.lemon.teachers[3] | 索引为3(第4个)老师的信息 |
| $..teachers[3] | 索引为3(第4个)老师的信息 |
| $.lemon.teachers[-2] | 倒数第2个老师的信息 |
| $..teachers[-2] | 倒数第2个老师的信息 |
| $..teachers[1,2] | 第2到第3个老师的信息 |
| $..teachers[:2] | 索引0(包含)到索引2(不包含)的老师信息 |
| $..teachers[1:3] | 索引1(包含)到索引3(不包含)的老师信息 |
| $..teachers[-2:] | 最后的两个老师的信息 |
| $..teachers[2:] | 索引2开始的所有老师信息 |
| $..teachers[?(@.addr)] | 所有包含地址的老师信息(jsonpath_rw不支持) |
| $.lemon.teachers[?(@.age < 20)] | 所有年龄小于20的年龄信息(jsonpath_rw不支持) |
一:使用jsonpath
安装jsonpath模块
pip install jsonpath==0.75
解析
# 1:导入相关模块
import json
import jsonpath
# 2: 准备json字符串
jsonStr = '''
{
"lemon": {
"teachers": [
{
"id": "101",
"name": "华华",
"addr": "湖南长沙",
"age": 25
},
{
"id": "102",
"name": "韬哥",
"age": 28
},
{
"id": "103",
"name": "Happy",
"addr": "广东深圳",
"age": 16
},
{
"id": "104",
"name": "歪歪",
"addr": "广东广州",
"age": 29
}
],
"salesmans": [
{
"id": "105",
"name": "毛毛",
"age": 17
},
{
"id": "106",
"name": "大树",
"age": 27
}
]
},
"avg": 25
}
'''
# 3:加载json字符串为json对象
json_obj = json.loads(jsonStr)
# 4:使用jsonpath模块的jsonpath方法提取信息
# eg1: 提取所有包含addr属性的老师信息,结果为list类型
results = jsonpath.jsonpath(json_obj,"$..teachers[?(@.addr)]")
print(results)
# 输出结果:[{'id': '101', 'name': '华华', 'addr': '湖南长沙', 'age': 25}, {'id': '103', 'name': 'Happy', 'addr': '广东深圳', 'age': 16}, {'id': '104', 'name': '歪歪', 'addr': '广东广州', 'age': 29}]
# eg2:提取所有年龄小于20岁的老师的name,结果为list类型
results2 = jsonpath.jsonpath(json_obj,"$.lemon.teachers[?(@.age < 20)].name")
print(results2)
# 输出结果为:['Happy']
二:使用jsonpath_rw
安装jsonpath_rw模块
pip install jsonpath-rw
解析
# 1:导入相关模块
import json
from jsonpath_rw import jsonpath, parse
# 2: 准备json字符串
jsonStr = '''
# 同上(略)
'''
# 3:加载为json对象
json_obj = json.loads(jsonStr)
# 4:采用parse创建jsonpath对象(该案例是得到所有的老师name)
jsonpath_expr = parse('$.lemon.teachers[*].name')
# 5:通过jsonPath检索json后返回匹配的数据,类型是DatumInContext的list
datumInContexts = jsonpath_expr.find(json_obj)
# 采用列表推导式检索出所有匹配的值
values = [datum.value for datum in datumInContexts]
print(values)
# 输出结果为:['华华', '韬哥', 'Happy', '歪歪']
# 案例2:提取索引为4的老师的name
jsonpath_expr = parse('$.lemon.teachers[3].name')
datumInContexts = jsonpath_expr.find(json_obj)
print(datumInContexts)
values = [datum.value for datum in datumInContexts]
print(values)
# 结果为:['歪歪']
更多jsonpath_rw用法参考:
https://www.cnblogs.com/aoyihuashao/p/8665873.html
使用 JsonPath 完成接口自动化测试中参数关联和数据验证(Python语言)的更多相关文章
- python装饰器在接口自动化测试中的应用
在讲解装饰器在接口自动化测试项目的应用之前,我们先来介绍一下python装饰器到底是个什么 装饰器 说装饰器就不得不提一下函数这个一等公民了,在python中函数有几个特性先来了解一下 函数的一些特性 ...
- struts2(三)---struts2中的服务端数据验证框架validate
struts2为我们提供了一个很好的数据验证框架–validate,该框架可以很方便的实现服务端的数据验证. ActionSupport类提供了一个validate()方法,当我们需要在某一个acti ...
- python接口自动化23-token参数关联登录(登录拉勾网)
前言 登录网站的时候,经常会遇到传token参数,token关联并不难,难的是找出服务器第一次返回token的值所在的位置,取出来后就可以动态关联了 登录拉勾网 1.先找到登录首页https://pa ...
- JsonPath在接口自动化中的应用
我理解jsonpath于json而言,就像是xpath在XML中的作用.用来确定json中某部分数据的语言.我更喜欢叫jsonpath表达式,因为这样好像是数学问题. 以前和小伙伴一起写接口自动化的时 ...
- 一篇文章告诉你Python接口自动化测试中读取Text,Excel,Yaml文件的方法
前言 不管是做Ui自动化和接口自动,代码和数据要分离,会用到Text,Excel,Yaml.今天讲讲如何读取文件数据 Python也可以读取ini文件,传送门 记住一点:测试的数据是不能写死在代码里面 ...
- python接口自动化-token参数关联登录(二)
原文地址https://www.cnblogs.com/yoyoketang/p/9098096.html 原文地址https://www.cnblogs.com/yoyoketang/p/68866 ...
- python接口自动化-token参数关联登录(登录拉勾网)
前言 登录网站的时候,经常会遇到传token参数,token关联并不难,难的是找出服务器第一次返回token的值所在的位置,取出来后就可以动态关联了 登录拉勾网 1.先找到登录首页https://pa ...
- 使用Jmeter执行接口自动化测试-如何初始化清空旧数据
需求分析: 每次执行完自动化测试,我们不会执行删除接口把数据删除,而需要留着手工测试,此时会导致下次执行测试有旧数据 我们手工可能也会新增数据,导致下次执行自动化测试有旧数据 下面介绍两种清空数据的方 ...
- 在.net MVC项目中使用ajax进行数据验证
1.首先要在网页引入应该引入的js文件 在这里回顾一下在模板页里面挖坑的技术 2.在html中使用html辅助方法 3.验证模型 4验证方法
随机推荐
- IOS 音频的 使用说明
说明 ● 简单来说,音频可以分为2种 ● 音效 • 又称“短音频”,通常在程序中的播放时长为1~2秒 • 在应用程序中起到点缀效果,提升整体用户体验 ● 音乐 • 比如游戏中的“背景音乐”,一般播放时 ...
- 进程、内存的理想与现实 VS 虚拟内存
理想情况下一个进程的运行,需要一块足够大的连续的内存进行装载. 现状: 1)内存不够大:分解进程内存空间. 2)内存不连续:内存映射.
- node.js 练习3 调用函数
(1)创建n3-1.js,并输入代码 (2)创建User.js ,并输入代码 (3)运行cmd (4)在浏览器上查看 (5) 再次查看cmd
- B4260 Codechef REBXOR
真是6块钱cpu(笑 爆炸入口 踹树练习(汗 对于二进制异或和弹性,我们可以贪心的来做. 瓶颈在于快速贪心. 我们可以维护一个trie树,储存异或前缀和.每次在trie树上贪心的跑. 正向and反向跑 ...
- JavaEE权限管理系统的搭建(二)--------聚合工程项目的创建和依赖关系
本项目是一个聚合工程,所以要先搭建一个聚合工程的框架 搭建完成的项目结构图如下: 首先创建父项目:pom类型 子模块:web层的搭建,war类型 把这个两个目录标记为对应的类型 其他子模块:和serv ...
- AngularJS 外部文件中的控制器其他实例
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- Python 初始—(多级字典)
字典中 嵌套字典 如同json 对象, data={ "msg":{ “xxx.com”:["a","b"] } } data.values ...
- [MYSQL笔记0]MYSQL的安装
mysql是一种关系型数据库管理系统.以mysql5.7版本为例,安装过程如下: 首先百度出mysql的官网,进入:(以下是自己安装失败的过程,直接下拉最后看大佬的安装过程吧,就是那个红红的网址) 找 ...
- 安装破解IDEA(个人使用)
安装的过程,许多的教程都会有,我在这里附上一两个链接吧:https://blog.csdn.net/newabcc/article/details/80601933 他这里也有破解过程,但是比较麻烦, ...
- xml的应用与dtd约束
1.xml的应用 *不同的系统之间的传输数据(qq消息传输) *用来表示生活中有关系的数据(省市区的包含关系) *经常用在文件配置 **比如现在连接数据库,肯定知道数据库的名称和密码及用户名. ...