做接口自动化,断言是比不可少的。如何快速巧妙的提取断言数据就成了关键,当然也可以提高用例的编写效率。笔者在工作中接触到了JMESPath,那到底该如何使用呢?带着疑惑一起往下看。
JMESPath是啥?JMESPath 是一种用于查询和转换 JSON 数据的简洁、强大的查询语言。它提供了一种灵活的方式来从复杂的 JSON 结构中提取所需的数据,并支持各种操作和函数,以满足不同的查询需求。
JMESPath如何使用?在使用 JMESPath 查询 JSON 数据之前,我们需要安装 jmespath 库。安装命令如下:
pip install jmespath
假设我们有以下的 JSON 数据:
- data = {
- "name": "Alice",
- "age": 25,
- "email": "alice@example.com"
- }
我们想要从中提取 "name" 属性的值。使用 JMESPath,我们可以编写以下代码:
- import jmespath
-
- expression = "name"
- result = jmespath.search(expression, data)
-
- print(result) # 输出:Alice
这里,我们定义了一个路径表达式 "name",然后使用 jmespath.search() 函数将该表达式应用于数据 data 上。结果会被存储在 result 变量中,并输出为 "Alice"。
当 JSON 数据具有嵌套结构时,可以使用点号 . 连接多个属性名来表示深层的属性访问。考虑以下 JSON 数据:
- data = {
- "person": {
- "name": "Alice",
- "age": 25,
- "email": "alice@example.com"
- }
- }
我们要提取 "name" 属性,可以使用以下路径表达式:
- expression = "person.name"
- result = jmespath.search(expression, data)
-
- print(result) # 输出:Alice
这里,我们将属性名 "person" 和 "name" 使用点号 . 连接起来,表示深层的属性访问。
假设我们有一个包含学生信息和他们的课程成绩的更复杂的 JSON 数据,如下所示:
- data = {
- "students": [
- {
- "name": "Alice",
- "courses": [
- {"name": "Math", "score": 95},
- {"name": "English", "score": 88}
- ]
- },
- {
- "name": "Bob",
- "courses": [
- {"name": "Math", "score": 75},
- {"name": "English", "score": 92}
- ]
- }
- ]
- }
-
现在,假设我们想要获取每个学生的数学成绩。可以通过以下表达式实现:
expression = "students[].courses[?name == 'Math'].score"
再次执行查询并打印结果:
- result = jmespath.search(expression, data)
- print(result)
输出结果将是一个包含每个学生数学成绩的列表:
[[95], [75]]
对于 JSON 中的列表属性,可以使用方括号 [index] 来指定索引位置来检索数据。假设我们有以下 JSON 数据:
- data = {
- "fruits": ["apple", "banana", "cherry"]
- }
我们想要提取第二个元素,即 "banana"。可以使用以下路径表达式:
- expression = "fruits[1]"
- result = jmespath.search(expression, data)
-
- print(result) # 输出:banana
这里,我们使用方括号 [1] 来指定索引位置,表示提取第二个元素。
JMESPath 提供了过滤器功能,使我们能够根据特定条件筛选出符合要求的数据。过滤器使用方括号 [?],后跟过滤条件。考虑以下 JSON 数据:
- data = {
- "users": [
- {"name": "Alice", "age": 25},
- {"name": "Bob", "age": 30},
- {"name": "Charlie", "age": 28}
- ]
- }
-
我们想要提取年龄大于 25 岁的用户对象。可以使用以下路径表达式进行过滤:
- expression = "users[?age > `25`]"
- result = jmespath.search(expression, data)
-
- print(result)
输出结果为:
[ {"name": "Bob", "age": 30}, {"name": "Charlie", "age": 28}]
这里,我们使用了过滤器 [?age > 25],表示只选择满足条件的用户对象。
JMESPath 还支持合并操作符 [],用于将多个查询结果合并成一个列表。假设我们想要获取所有学生的所有课程名称。可以使用合并操作符 [] 来实现:
- data = {
- "students": [
- {
- "name": "Alice",
- "courses": [
- {"name": "Math", "score": 95},
- {"name": "English", "score": 88}
- ]
- },
- {
- "name": "Bob",
- "courses": [
- {"name": "Math", "score": 75},
- {"name": "English", "score": 92}
- ]
- }
- ]
- }
-
获取所有学生的所有课程名称:
- expression = "students[].courses[].name"
- result = jmespath.search(expression, data)
- print(result)
输出结果为:
['Math', 'English', 'Math', 'English']
JMESPath 还支持对查询结果进行排序和切片操作。假设我们想要按学生年龄进行降序排序。可以使用排序函数 sort() 和逆序函数 reverse() 来实现:
- data = {
- "students": [
- {"name": "Alice", "age": 20},
- {"name": "Bob", "age": 22},
- {"name": "Charlie", "age": 21}
- ]
- }
-
得到按年龄降序排列的学生列表:
- expression = "students | sort_by(@, &age) | reverse(@)"
-
- result = jmespath.search(expression, data)
- print(result) # [{'name': 'Bob', 'age': 22}, {'name': 'Charlie', 'age': 21}, {'name': 'Alice', 'age': 20}]
-
切片
- data = {
- "fruits": ["apple", "banana", "cherry"]
- }
利用切片获取第一个元素
- import jmespath
-
- data = {
- "fruits": ["apple", "banana", "cherry"]
- }
- expression = "fruits[0:1]"
- result = jmespath.search(expression, data)
-
- print(result) # ['apple']
-
使用管道符号(|),将当前节点的结果传到管道符右侧继续投影。
- data = {
- "students": [
- {"name": "Alice", "age": 20},
- {"name": "Bob", "age": 22},
- {"name": "Charlie", "age": 21}
- ]
- }
-
获取所有的姓名:
- expression = "students[*].name"
- result = jmespath.search(expression, data)
- print(result) # ['Alice', 'Bob', 'Charlie']
如果在此基础上想要得到Bob这个值。我们尝试使用索引:
- expression = "students[*].name[1]"
- result = jmespath.search(expression, data)
- print(result) # []
发现执行结果是一个空列表,这个时候怎么办呢?使用管道表达式,
expression = "students[*].name | [1]"
计算列表长度
- data = {
- "students": [
- {"name": "Alice", "age": 20},
- {"name": "Bob", "age": 22},
- {"name": "Charlie", "age": 21}
- ]
- }
-
- expression = "length(students)" # 也可以这样写expression = "students | length(@)"
- result = jmespath.search(expression, data)
- print(result) # 3
-
length就是jmespath内置的函数。
当然还有一些其他常用的内置函数,比如:
starts_with(str, prefix): 检查字符串是否以指定前缀开头。ends_with(str, suffix): 检查字符串是否以指定后缀结尾。contains(str, substring): 检查字符串是否包含子字符串。length(arr): 返回数组的长度。jmespath确实很强大,通过逐步学习和实践,可以更好地掌握 JMESPath 的功能和灵活性。
下面是配套学习资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!【100%无套路免费领取】

被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!
涵盖以下这些面试题板块:
1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux
6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础

