Python 使用 JsonPath 完成接口自动化测试中参数关联和数据验证

背景:

  1. 接口自动化测试实现简单、成本较低、收益较高,越来越受到企业重视
  2. RESTFul 风格的 API 设计大行其道
  3. JSON 成为主流的轻量级数据交换格式

痛点

接口关联

  • 接口关联也称为关联参数。在应用业务接口中,完成一个业务功能时,有时候一个接口可能不满足业务的整个流程逻辑,需要多个接口配合使用,简单的案例如:B 接口的成功调用依赖于 A 接口,需要在 A 接口的响应数据(response)中拿到需要的字段,在调用 B 接口的时候,传递给 B 接口作为 B 接口请求参数,拿到后续响应的响应数据。
  • 接口关联通常可以使用正则表达式去提取需要的数据,但对于 JSON 这种简洁、清晰层次结构、轻量级的数据交互格式,使用正则未免有点杀鸡用牛刀的感觉(是的,因为我不擅长写正则表达式),我们需要更加简单、直接的提取 JSON 数据的方式。
  • 数据验证

  • 这里的数据验证指的是对响应结果进行数据的校验
  • 接口自动化测试中,对于简单的响应结果(JSON),可以直接和期望结果进行比对,判断是否完全相等即可。如
  •      {"status":1,"msg":"登录成功"}
  • 对于格式较复杂,尤其部分数据存在不确定性、会根据实际情况变化的响应结果,简单的判断是否完全相等(断言)通常会失败。如:
  •   {"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 可以通过点语法来检索数据,如:
  •   $.store.book[0].title 
  • 也可以使用中括 []的形式,如
  •   $['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 jsonimport 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 jsonfrom 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的listdatumInContexts = jsonpath_expr.find(json_obj)# 采用列表推导式检索出所有匹配的值values = [datum.value for datum in datumInContexts]print(values)# 输出结果为:['华华', '韬哥', 'Happy', '歪歪']# 案例2:提取索引为4的老师的namejsonpath_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://pypi.org/project/jsonpath-rw/

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

    上一篇 2022年2月19日
    下一篇 2022年2月19日

    相关推荐