接口测试中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 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)
# 结果为:['歪歪']

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

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
APIfox是一款接口测试工具,它支持使用JavaScript编写测试脚本,对接口进行自动化测试,并可以使用断言来验证接口返回结果是否符合预期。以下是使用APIfox进行接口测试并编写断言的一般步骤: 1. 在APIfox创建一个测试项目,并添加需要测试的接口。 2. 在测试项目创建一个测试用例,并选择需要测试的接口。 3. 在测试用例编写JavaScript脚本,发送接口请求并获取接口返回结果。 4. 对接口返回结果进行断言验证,判断是否符合预期。例如,可以验证接口返回的状态码、响应头、响应体的某个字段等。 以下是一个使用APIfox进行接口测试并编写断言的示例代码: ```javascript // 发送接口请求并获取接口返回结果 var response = $http.get("http://api.example.com/users"); // 断言验证接口返回的状态码是否为200 $assert.equal(response.status, 200, "接口返回状态码不正确"); // 断言验证接口返回的响应体是否包含名称为"张三"的用户 var users = response.data; var hasUser = false; for (var i = 0; i < users.length; i++) { if (users[i].name === "张三") { hasUser = true; break; } } $assert.isTrue(hasUser, "接口返回的用户列表不包含名称为\"张三\"的用户"); ``` 在上述代码使用`$http.get`发送接口请求并获取接口返回结果,然后使用`$assert`进行断言验证,判断接口返回的状态码和响应体是否符合预期。如果断言验证失败,将会输出自定义的错误信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值