• 提高接口自动化测试效率:使用 JMESPath 实现断言和数据提取


    前言

    接口自动化,断言是比不可少的。如何快速巧妙的提取断言数据就成了关键,当然也可以提高用例的编写效率。笔者在工作中接触到了JMESPath,那到底该如何使用呢?带着疑惑一起往下看。

    JMESPath是啥?

    JMESPath 是一种用于查询和转换 JSON 数据的简洁、强大的查询语言。它提供了一种灵活的方式来从复杂的 JSON 结构中提取所需的数据,并支持各种操作和函数,以满足不同的查询需求。

    JMESPath如何使用?

    在使用 JMESPath 查询 JSON 数据之前,我们需要安装 jmespath 库。安装命令如下:

    pip install jmespath
    简单路径表达式

    假设我们有以下的 JSON 数据:

    1. data = {
    2. "name": "Alice",
    3. "age": 25,
    4. "email": "alice@example.com"
    5. }

    我们想要从中提取 "name" 属性的值。使用 JMESPath,我们可以编写以下代码:

    1. import jmespath
    2. expression = "name"
    3. result = jmespath.search(expression, data)
    4. print(result) # 输出:Alice

    这里,我们定义了一个路径表达式 "name",然后使用 jmespath.search() 函数将该表达式应用于数据 data 上。结果会被存储在 result 变量中,并输出为 "Alice"

    嵌套属性访问

    当 JSON 数据具有嵌套结构时,可以使用点号 . 连接多个属性名来表示深层的属性访问。考虑以下 JSON 数据:

    1. data = {
    2. "person": {
    3. "name": "Alice",
    4. "age": 25,
    5. "email": "alice@example.com"
    6. }
    7. }

    我们要提取 "name" 属性,可以使用以下路径表达式:

    1. expression = "person.name"
    2. result = jmespath.search(expression, data)
    3. print(result) # 输出:Alice

    这里,我们将属性名 "person" 和 "name" 使用点号 . 连接起来,表示深层的属性访问。

    复杂嵌套查询

    假设我们有一个包含学生信息和他们的课程成绩的更复杂的 JSON 数据,如下所示:

    1. data = {
    2.    "students": [
    3.       {
    4.            "name": "Alice",
    5.            "courses": [
    6.               {"name": "Math", "score": 95},
    7.               {"name": "English", "score": 88}
    8.           ]
    9.       },
    10.       {
    11.            "name": "Bob",
    12.            "courses": [
    13.               {"name": "Math", "score": 75},
    14.               {"name": "English", "score": 92}
    15.           ]
    16.       }
    17.   ]
    18. }

    现在,假设我们想要获取每个学生的数学成绩。可以通过以下表达式实现:

    expression = "students[].courses[?name == 'Math'].score"

    再次执行查询并打印结果:

    1. result = jmespath.search(expression, data)
    2. print(result)

    输出结果将是一个包含每个学生数学成绩的列表:

    [[95], [75]]
    列表索引

    对于 JSON 中的列表属性,可以使用方括号 [index] 来指定索引位置来检索数据。假设我们有以下 JSON 数据:

    1. data = {
    2. "fruits": ["apple", "banana", "cherry"]
    3. }

    我们想要提取第二个元素,即 "banana"。可以使用以下路径表达式:

    1. expression = "fruits[1]"
    2. result = jmespath.search(expression, data)
    3. print(result) # 输出:banana

    这里,我们使用方括号 [1] 来指定索引位置,表示提取第二个元素。

    过滤器

    JMESPath 提供了过滤器功能,使我们能够根据特定条件筛选出符合要求的数据。过滤器使用方括号 [?],后跟过滤条件。考虑以下 JSON 数据:

    1. data = {
    2.    "users": [
    3.       {"name": "Alice", "age": 25},
    4.       {"name": "Bob", "age": 30},
    5.       {"name": "Charlie", "age": 28}
    6.   ]
    7. }

    我们想要提取年龄大于 25 岁的用户对象。可以使用以下路径表达式进行过滤:

    1. expression = "users[?age > `25`]"
    2. result = jmespath.search(expression, data)
    3. print(result)

    输出结果为:

    [    {"name": "Bob", "age": 30},    {"name": "Charlie", "age": 28}]

    这里,我们使用了过滤器 [?age > 25],表示只选择满足条件的用户对象。

    合并操作

    JMESPath 还支持合并操作符 [],用于将多个查询结果合并成一个列表。假设我们想要获取所有学生的所有课程名称。可以使用合并操作符 [] 来实现:

    1. data = {
    2.    "students": [
    3.       {
    4.            "name": "Alice",
    5.            "courses": [
    6.               {"name": "Math", "score": 95},
    7.               {"name": "English", "score": 88}
    8.           ]
    9.       },
    10.       {
    11.            "name": "Bob",
    12.            "courses": [
    13.               {"name": "Math", "score": 75},
    14.               {"name": "English", "score": 92}
    15.           ]
    16.       }
    17.   ]
    18. }

    获取所有学生的所有课程名称:

    1. expression = "students[].courses[].name"
    2. result = jmespath.search(expression, data)
    3. print(result)

    输出结果为:

    ['Math', 'English', 'Math', 'English']
    排序和切片

    JMESPath 还支持对查询结果进行排序和切片操作。假设我们想要按学生年龄进行降序排序。可以使用排序函数 sort() 和逆序函数 reverse() 来实现:

    1. data = {
    2.    "students": [
    3.       {"name": "Alice", "age": 20},
    4.       {"name": "Bob", "age": 22},
    5.       {"name": "Charlie", "age": 21}
    6.   ]
    7. }

    得到按年龄降序排列的学生列表:

    1. expression = "students | sort_by(@, &age) | reverse(@)"
    2. result = jmespath.search(expression, data)
    3. print(result) # [{'name': 'Bob', 'age': 22}, {'name': 'Charlie', 'age': 21}, {'name': 'Alice', 'age': 20}]

    切片

    1. data = {
    2. "fruits": ["apple", "banana", "cherry"]
    3. }

    利用切片获取第一个元素

    1. import jmespath
    2. data = {
    3.    "fruits": ["apple", "banana", "cherry"]
    4. }
    5. expression = "fruits[0:1]"
    6. result = jmespath.search(expression, data)
    7. print(result) # ['apple']
    管道

    使用管道符号(|),将当前节点的结果传到管道符右侧继续投影。

    1. data = {
    2.    "students": [
    3.       {"name": "Alice", "age": 20},
    4.       {"name": "Bob", "age": 22},
    5.       {"name": "Charlie", "age": 21}
    6.   ]
    7. }

    获取所有的姓名:

    1. expression = "students[*].name"
    2. result = jmespath.search(expression, data)
    3. print(result) # ['Alice', 'Bob', 'Charlie']

    如果在此基础上想要得到Bob这个值。我们尝试使用索引:

    1. expression = "students[*].name[1]"
    2. result = jmespath.search(expression, data)
    3. print(result) # []

    发现执行结果是一个空列表,这个时候怎么办呢?使用管道表达式,  |

    expression = "students[*].name | [1]"
    内置函数

    计算列表长度

    1. data = {
    2.    "students": [
    3.       {"name": "Alice", "age": 20},
    4.       {"name": "Bob", "age": 22},
    5.       {"name": "Charlie", "age": 21}
    6.   ]
    7. }
    8. expression = "length(students)"  # 也可以这样写expression = "students | length(@)"
    9. result = jmespath.search(expression, data)
    10. 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、计算机基础

      全套资料获取方式:点击下方小卡片自行领取即可

  • 相关阅读:
    曝一段十多年前的“情史”!
    Xilinx ZYNQ 7000学习笔记五(Xilinx SDK 烧写镜像文件)
    01-Window10安装Redis
    java继承性
    ETH POS 2.0 Staking 测试网质押流程
    pgpool密码验证失败问题
    基于虚拟阻抗的下垂控制——孤岛双机并联Simulink仿真
    解密铭控传感从数字压力表到多品类物联感知硬件的发展史!
    MYSQL进阶
    性能测试理论1 | 性能测试难点问题梳理
  • 原文地址:https://blog.csdn.net/weixin_47648853/article/details/133926295