接口测试 04 -- Jsonpath断言、接口关联处理

news2025/1/12 21:52:15

1. JsonPath基本介绍

1.1 JsonPath简介

JsonPath是一种用于在JSON数据中定位和提取特定数据的表达式语言。它类似于XPath用于XML的定位和提取,可以帮助我们灵活地从复杂的JSON结构中获取所需的数据。

 1.2 JsonPath的特点

● JsonPath可处理的报文类型为字典类型

● 通过JsonPath成功获得的内容,会以list的形式进行返回,也就意味着你的 JsonPath是可以有一个值或者多个值同时存在的。

● 如果要基于JsonPath来处理json数据,就一定要去同步处理list

● JsonPath定义中,如果表达式出现错误,则会返回False(布尔类型的值)

● JsonPath要么返回False,要么返回list

1.3 JsonPath安装

pip install jsonpath    # 安装命令
pip show jsonpath       # 安装效验

1.4 JsonPath实际运行场景

对应做软件测试来说:

1. 主要能够通过这个方式提取数据
2. 业务场景: 断言 、接口关联

常规的报文也避免不了比较复杂的情况,如下所示包含了一个人员的信息,包括姓名、年龄、邮箱、地址、爱好、教育背景和参与的项目。
它展示了JSON数据的嵌套结构和多种数据类型的使用,那么我们应该如何进行解决呢?
{
"name": "Alice",
"age": 25,
"email": "alice@example.com",
"address": {
"street": "456 Elm Street",
"city": "Los Angeles",
"country": "USA"
},
"hobbies": ["reading", "traveling", "cooking"],
"education": [
{
"degree": "Bachelor's",
"major": "Computer Science",
"university": "ABC University",
"year": 2018
},
{
"degree": "Master's",
"major": "Business Administration",
"university": "XYZ University",
"year": 2020
}
],
"projects": [
{
"name": "Project A",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"contributors": ["John", "Sarah", "Mike"],
"completed": "true"
},
{
"name": "Project B",
"description": "Nulla vel sagittis elit. Vivamus auctor massa in lacinia pellentesque.",
"contributors": ["Alice", "David"],
"completed": "false"
}
],
"is_active": "true"
}

举一个栗子:提取上面这段代码中education里的年份值

更多提取信息,语法格式,先下面“JsonPath基本格式规范-示例参考

从上图可以看出:返回的数据类型是列表

1.5 JsonPath基本格式规范

以下是一些JsonPath的常用语法和示例:

附:jsonpath在线解析器 http://www.atoolbox.net/Tool.php?Id=792

$ 根节点,也是所有JsonPath表达式的开始
. 表示获取子节点
.. 表示获取所有符合条件的内容
* 代表所有的元素节点
[index] 表示迭代器的标示(可以用于处理下标等情况)
[,] 表示多个结果的选择
[start:end] 指定范围内的元素
?(@.property == value) 表示过滤操作 # 比较运算符
@ 表示当前节点
示例参考:
① 基本语法
$ :根节点,也是所有JsonPath表达式的开始
. :当前节点
.. :递归下级节点
② 属性操作
$.property :选择指定属性
$['property'] :选择指定属性,属性名带有特殊字符时使用

③ 数组操作(含头不含尾)

$.array[index] :选择指定索引处的元素
$.array[start:end] :选择指定范围内的元素

 ④ 过滤器(比较运算符都可以用)

$.array[?(@.property == value)] :根据条件过滤数组元素
$.array[?(@.property > value)] :根据条件过滤数组元素

⑤ 路径组合

$.parent.child :选择父节点下的子节点
$.parent[*].child :选择父节点下所有子节点的某个属性

1.6 JsonPath断言实例

一个登陆接口的正向用例:

断言 :提取响应数据和期望数据进行对比

import jsonpath
import requests
import json

# 完整的请求url
url = "http://xxxx域名/index.php?s=/api/user/login" 

# 公共参数
pulic_data = {"application": "app", "application_client_type": "weixin"}
# 登陆接口请求参数
data = {"accounts": "hailey", "pwd": "hailey123", "type": "username"}

json_data = json.dumps(data)  # 将请求参数转为json格式

# 指定请求头的参数的数据格式为json
header = {'Content-Type':'application/json;charset=utf-8'}

# 发送请求    
res = requests.post(url,params=pulic_data,headers=header,data=json_data)

print(res.json())

exData = "登录成功"   # 期望结果

# 实际结果:最后记得加索引,不然会报错
SjData = jsonpath.jsonpath(res.json(),"$.msg")[0]  
# 断言 期望结果结果等于实际结果,并格式化输出期望结果、实际结果
assert exData == SjData,"期望结果是:{0},实际结果是:{1}".format(exData,SjData)

所有工具中的断言都一样,如果断言成功,则不会显示断言信息,也不会报错

如果断言失败,则报错信息中显示断言信息

2. 接口关联

2.1 接口关联意义

接口关联是在进行接口测试时,将一个接口的返回结果中的某些数据提取出来,然后作为后续接口请求的参数或者验证的依据。通过接口关联,可以实现接口间的数据传递和依赖关系的建立。

2.2 接口关联类型

接口关联通常分为两种类型:请求关联和响应关联。
1. 请求关联
提取关键参数 :在一个接口的请求中,某些参数的值是由之前接口的响应结果提供的。需要提取出这些关键参数,并将其作为后续接口的请求参数。
例如,一个接口的请求中需要使用到某个用户的登录令牌(token),可以通过在登录接口的响应结果中提取出令牌(token),然后在后续接口的请求中使用。
----------->>>
2. 响应关联
验证关键数据 :在一个接口的响应结果中,某些数据是需要验证的,可以将这些数据提取出来,并进行断言或者其他验证操作。
例如,一个接口的响应结果中包含了某个订单的状态信息,可以将该状态信息提取出来,然后进行断言,验证订单是否处于正确的状态。

2.3 加入购物车案例

这里还是基于上个案例的登录接口(某电商平台):

1. 首先登录成功,提取token值。

2. 通过提取的token,将商品加入购物车。

使用josnpath提取token

第一步:将打印信息换成text文件,方便接下来去调试

import json
import requests
import jsonpath

url = "http://xxxx域名/index.php?s=/api/user/login" 
pulic_data = {"application": "app", "application_client_type": "weixin"}
data = {"accounts": "hailey", "pwd": "hailey123", "type": "username"}

header = {'Content-Type': 'application/json; charset=utf-8'}
json_data = json.dumps(data)

# --------------------发送接口请求---------------------------
res = requests.post(url, params=pulic_data, headers=header,data=json_data) # 正确的演示

# --------------------获取响应数据---------------------------
print(res.text)    # 改成获取text文本内容


# --------------------获取数据进行断言处理---------------------------
exData = "登录成功"
SjData = jsonpath.jsonpath(res.json(),"$.msg")[0]
assert exData == SjData, "期望结构是:{0},实际结果是:{1}".format(exData, SjData)

第二步:将上一步的代码运行,复制控制台输出的响应内容,全部黏贴到json在线工具中,美化一下格式:JSON在线解析及格式化验证 - JSON.cn

第三步:复制黏贴美化后的响应内容,到josnpath在线工具中,进行调试

ps:如果代码能力强的,可以跳过这两步,直接写josnpath提取token的代码

josnpath提取响应信息中的token,有上面两种写法,第二种更简单

第四步:去完善代码

import json
import requests
import jsonpath

url = "http://xxxx域名/index.php?s=/api/user/login" 
pulic_data = {"application": "app", "application_client_type": "weixin"}
data = {"accounts": "hailey", "pwd": "hailey123", "type": "username"}

header = {'Content-Type': 'application/json; charset=utf-8'}
json_data = json.dumps(data)

# --------------------发送接口请求---------------------------
res = requests.post(url, params=pulic_data, headers=header,data=json_data) # 正确的演示

# --------------------获取响应数据---------------------------
print("响应信息:",res.text)    # 改成获取text文本内容

# --------------------获取数据进行断言处理---------------------------
exData = "登录成功"
SjData = jsonpath.jsonpath(res.json(),"$.msg")[0]
assert exData == SjData, "期望结构是:{0},实际结果是:{1}".format(exData, SjData)

# --------------------获提取token值---------------------------
token =jsonpath.jsonpath(res.json(),"$..token")[0]
print("提取出来的token值:",token)

加入购物车

完整代码:

import json
import requests
import jsonpath

url = "http://xxxx域名/index.php?s=/api/user/login" 
pulic_data = {"application": "app", "application_client_type": "weixin"}
data = {"accounts": "hailey", "pwd": "hailey123", "type": "username"}

header = {'Content-Type': 'application/json; charset=utf-8'}
json_data = json.dumps(data)

# --------------------发送接口请求---------------------------
res = requests.post(url, params=pulic_data, headers=header,data=json_data) # 正确的演示

# --------------------获取响应数据---------------------------
print("响应信息:",res.text)    # 改成获取text文本内容

# --------------------获取数据进行断言处理---------------------------
exData = "登录成功"
SjData = jsonpath.jsonpath(res.json(),"$.msg")[0]
assert exData == SjData, "期望结构是:{0},实际结果是:{1}".format(exData, SjData)

# --------------------获提取token值---------------------------
token =jsonpath.jsonpath(res.json(),"$..token")[0]
print("提取出来的token值:",token)

# --------------------加入购物车---------------------------
# 加入购物车请求参数
data = {
    "goods_id":"10", # 商品id
    "spec": "",      # 商品规格,无规格
    "stock": 1       # 加入数量
}

# 公共参数
params = {
    "application": "app",
    "application_client_type": "weixin",
    "token": token
}
res = requests.post(url="http://xxxx域名/index.php?s=api/cart/save", params=params, json=data)
print(res.json())

打开web页面:也显示加入成功

拿到对应的项目,一定要梳理出来对应的业务流程及它对应接口之间的关联关系
任何项目:都需要理解需求、业务流程

=====================================================================

基于这个思路:还可以梳理出不同的测试场景
1. 浏览商品--加入购物车 (有规格/无规格) --从购物车去提交订单
a.选择商品[一般对应列表都是会有 (购物车)列表接口,都会有id)
b.选择对应的地址
c.选择支付方式)--订单支付

---------------->>>
2. 浏览商品--加入购物车--从购物车去提交订单--取消订单

---------------->>>
3. 浏览商品--提交订单
a.从数据库找商品表 (找到商品名称字段)
b.从页面上获取 (id,一般会在页面对应的url中)

=====================================================================

可以看出,接口测试,与功能测试的思路、场景都是一样的

再换一个有商品规格的商品,加入购物车

import json
import requests
import jsonpath

url = "http://xxxx域名/index.php?s=/api/user/login" 
pulic_data = {"application": "app", "application_client_type": "weixin"}
data = {"accounts": "hailey", "pwd": "hailey123", "type": "username"}

header = {'Content-Type': 'application/json; charset=utf-8'}
json_data = json.dumps(data)

# --------------------发送接口请求---------------------------
res = requests.post(url, params=pulic_data, headers=header,data=json_data) # 正确的演示

# --------------------获取响应数据---------------------------
print("响应信息:",res.text)    # 改成获取text文本内容

# --------------------获取数据进行断言处理---------------------------
exData = "登录成功"
SjData = jsonpath.jsonpath(res.json(),"$.msg")[0]
assert exData == SjData, "期望结构是:{0},实际结果是:{1}".format(exData, SjData)

# --------------------获提取token值---------------------------
token =jsonpath.jsonpath(res.json(),"$..token")[0]
print("提取出来的token值:",token)

# --------------------加入购物车---------------------------
# 加入购物车请求参数,有规格值
data = {
    "goods_id": "11",
    "spec": [
        {
            "type": "尺寸",
            "value": "L"
        }
    ],
    "stock": "10"}

# 公共参数
params = {
    "application": "app",
    "application_client_type": "weixin",
    "token": token
}
res = requests.post(url="http://xxxx域名/index.php?s=api/cart/save", params=params, json=data)
print(res.json())

再加一个查看购物车接口、并提取购物车列表Id:

import json
import requests
import jsonpath

url = "http://xxxx域名/index.php?s=/api/user/login" 
pulic_data = {"application": "app", "application_client_type": "weixin"}
data = {"accounts": "hailey", "pwd": "hailey123", "type": "username"}

header = {'Content-Type': 'application/json; charset=utf-8'}
json_data = json.dumps(data)

# --------------------发送接口请求---------------------------
res = requests.post(url, params=pulic_data, headers=header,data=json_data) # 正确的演示

# --------------------获取响应数据---------------------------
print("响应信息:",res.text)    # 改成获取text文本内容

# --------------------获取数据进行断言处理---------------------------
exData = "登录成功"
SjData = jsonpath.jsonpath(res.json(),"$.msg")[0]
assert exData == SjData, "期望结构是:{0},实际结果是:{1}".format(exData, SjData)

# --------------------获提取token值---------------------------
token =jsonpath.jsonpath(res.json(),"$..token")[0]
print("提取出来的token值:",token)

# --------------------加入购物车---------------------------
# 加入购物车请求参数,有规格值
data = {
    "goods_id": "11",
    "spec": [
        {
            "type": "尺寸",
            "value": "L"
        }
    ],
    "stock": "10"}

# 公共参数
params = {
    "application": "app",
    "application_client_type": "weixin",
    "token": token
}
res = requests.post(url="http://xxxx域名/index.php?s=api/cart/save", params=params, json=data)
print(res.json())


# --------------------购物车列表---------------------------
# 公共参数,查看购物车没有请求参数
params = {
    "application": "app",
    "application_client_type": "weixin",
    "token": token
}
res = requests.get(url="http://xxx域名/index.php?s=api/cart/index", params=params)
print(res.json())
cardid  =jsonpath.jsonpath(res.json(),"$..id")[0] # 推荐的用法
print("提取出来的商品id:>>",cardid)

总结

思路

web自动化、api接口自动化,本质上都是模拟用户操作,所以手工测试有哪些步骤、自动化同样也有哪些步骤。

列表页面:商品列表、购物列表,任何列表都有增删改查,所以都会有对应的接口,接口关联依赖上一个接口的数据,一般都会有一个 (列表)唯一值 id。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1401512.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

运动的解析:从机械运动到自由落体,探索物体运动的基本规律与数学描述

文章目录 一、机械运动(一)运动概念(二)运动形式(三)参照物 二、质点(一)理想化模型(二)质点概念 三、位移和路程(一)位移&#xff08…

python基础学习-01

Python 是一种简单易学并且结合了解释性、编译性、互动性和面向对象的脚本语言。Python提供了高级数据结构,它的语法和动态类型以及解释性使它成为广大开发者的首选编程语言。 Python 是解释型语言: 开发过程中没有了编译这个环节。类似于PHP和Perl语言。…

如操作系统的心跳,运行状况无可逃避:Shell脚本揭示系统鲜活秘密!

简介 Ubuntu 系统保姆监控脚本,全自动化解读系统运行状态!脚本轻量化、资源节约,并且能够定期检测硬盘容量、内存占用和缓存情况。一旦发现缓存占用过高,即刻自动清理缓存,并将结果写入指定目录的日志文件中。日志文件…

鸿蒙开发-UI-布局-相对布局

鸿蒙开发-UI-布局 鸿蒙开发-UI-布局-线性布局 鸿蒙开发-UI-布局-层叠布局 鸿蒙开发-UI-布局-弹性布局 文章目录 前言 一、基本概念 二、设置依赖 1.锚点设置 2.设置相对于锚点的对齐位置 三、使用场景 总结 前言 上文详细学习常见布局方式-弹性布局,学习弹性布局容…

知识图谱KG+大模型LLM

LLM-based KG KnowLM OpenSPGKG-based RAG 基本原理 从query出发的语义解析 pre-LLM方法 思想:直接将问题解析为对应的逻辑表达式,然后到知识图谱中查询。 方法:通常包含逻辑表达式、语义解析算法、语义解析模型训练三部分。一般步骤是将问句…

NODE介绍和环境安装

浏览器是JS的前端运行环境 Node.js是JS的后端运行环境 Node.js中无法调用DOM和BOM等浏览器内置API 基于Express框架,快速构建web应用 基于Electron框架,构建跨平台桌面应用 基于restify框架快速构建API接口项目 读写数据库 下载Node.js环境 网址&…

linux下的nginx相关配置练习

1.基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab!!! [rootlocalhost ~]# systemctl stop firewalld.service #关闭防火墙 [rootlocalhost ~]# setenforce 0 #关闭selinux [rootlocalhost www]# vim /etc/nginx/conf.d/test_ope…

python 之 指定小数的输出

文章目录 **使用 round() 函数:****使用字符串格式化:****使用f-字符串:****使用 decimal 模块:** 在Python中,可以使用不同的方法来指定浮点数的小数位数。以下是其中一些常见的方式: 使用 round() 函数&…

mapboxGL中的航线动画

概述 借用上篇文章中二阶贝塞尔曲线的生成,本文实现mapboxGL中的航线动画。 效果 实现 1. 初始化地图 const from [101.797439042302, 36.5937248286007]; const to [106.9733, 35.217]; const points new ArcLine(from, to); const line new Geometry(poin…

【Qt】—— Qt的基本介绍

目录 (一)什么是Qt (二) Qt的发展史 (三)Qt⽀持的平台 (四) Qt版本 (五)Qt的优点 (六)Qt的应⽤场景 (七&#xff09…

tag 标签

tag 标签 在使用 Git 版本控制的过程中,会产生大量的版本。如果我们想对某些重要版本进行记录,就可以给仓库历史中的某一个commit 打上标签,用于标识。 在本章中,我们将会学习如何列出已有的标签、如何创建和删除新的标签、以及…

Windows使用wsl2安装docker教程

windows环境搭建专栏🔗点击跳转 win系统环境搭建(十一)——Windows安装docker 文章目录 win系统环境搭建(十一)——Windows安装docker1.搭建WSL2环境1.1 docker官网对环境要求的描述[System requirements](https://do…

JavaScript 学习笔记(WEB APIs Day3)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度,分享学习笔记,希望能对大家有所帮助。推荐先按顺序阅读往期内容: 1. JavaScript 学习笔记(Day1) 2. JavaSc…

云服务器定价_云服务器价格_云主机计费模式_腾讯云

腾讯云服务器租用价格表:轻量应用服务器2核2G3M价格62元一年、2核2G4M价格118元一年,540元三年、2核4G5M带宽218元一年,2核4G5M带宽756元三年、轻量4核8G12M服务器446元一年、646元15个月,云服务器CVM S5实例2核2G配置280.8元一年…

Mysql运维篇(二) 主从复制

一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人,如有侵权请留言,我及时删除。 一、主从复制的原理 主库会生成一个I/O操作线程进去写的的操作,而从库则生成两个线程,其…

08. 面向对象编程(二)

目录 1、前言 2、多重继承 2.1、潜在的问题 3、Property 4、staticmethod 5、运算符重载 5.1、加法运算符 的重载 5.2、字符串表示运算符 str() 的重载 5.3、索引运算符 [] 的重载 6、小结 1、前言 上一篇文章中,我们介绍了面向对象编程的类和实例&…

安规电容的知识

1、常见安规电容有哪些? 一般我们所说的安规电容也就有两种,一种就是X安规电容(X1/X2/X3安规电容),还有一种是Y电容(最常见的是Y1和Y2安规电容)。 2、x电容的位置 火线零线间的是X电容。x电容用…

保证缓存一致性的常用套路

缓存更新的套路 看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作,另一个是查…

傲梅轻松备份-备份rocky9,并还原备份

傲梅分区助手磁盘备份功能免费;备份iso镜像不支持linux,好像只能备份window;且备份镜像收费功能,永久授权99; 概述: 1)新建备份U盘 2)新建虚拟机,配置虚拟机&#xff…

C++将信息输入到文件内

第一步检查文件是否打开&#xff0c;用到头文件&#xff1a; #include <fstream> #include <sstream> 文件打开的函数为 file.isopen() 信息输入到文件应该为 file << "" << value; 注意是file<< 如图 定义file ofstream f…