JsonPath应用及断言 重要
自动化要解决的核心问题 :进行自动测试-自动校验(进行结果的校验
- 主要能够通过这个方式提取数据
- 业务场景:断言 、接口关联
{key:value}网址:附:在线解析 JSONPath解析器 - 一个工具箱 - 好用的在线工具都在这里!
json的基本应用:\
格式: $路径基础的应用【必须掌握的】
# 1. $.key
$.name
# 2. $..key --- 从任意的目录去找
$.name列表:可以通过下标去进行获取:从0开始
$.hobbies[2]$..year --- 所有的年语法:
$.key[?(@.key==year)]区间:左闭右开(后面的下标需要+1)
$.projects[0:1]# 获取根目录下的子字段:获取用户名
$.name
# 获取根目录下的字典中的数据:获取地址中的城市("country": "USA")
$.address.country
# 获取根目录下的列表中的某个数据:获取教育经历
$.education[0]
# 获取根目录下的列表中的所有数据中的某个字段:获取教育经历中的年
$.education[0:].year
# 获取根目录下的列表中满足某个条件的数据:获取教育经历中的年等于2020 的数据,== \!=
$.education[?(@.year==2020)]
# 获取所有的数据
$.*
我们把数据放入pycharm中,在里面编写json代码
# 返回的数据类型都是列表格式【重点】
res = jsonpath.jsonpath(data, "$..year")
print(res)
print(type(res))res = jsonpath.jsonpath(data, "$.name")
print(res) # 列表
print(res[0]) # 下标获取某个值
print(type(res))
代码示例如下
import jsonimport requests
import jsonpath# 案例:登录接口 :
# 接口请求的四要素:URL\ 请求方法 \请求参数\响应数据
# URL
url = "http://shop-xo.hctestedu.com/index.php?s=/api/user/login"
# 请求参数-- 公共参数-- url
pulic_data = {"application": "app", "application_client_type": "weixin"}
# 请求参数-- body (你的body数据是要以json进行提交,参数:json)
data = {"accounts": "hami", "pwd": "123456", "type": "username"}
# 请求头
header = {'Content-Type': 'application/json; charset=utf-8'}
# 请求头是json,所以数据类型需要转
json_data = json.dumps(data)# --------------------发送接口请求---------------------------
res = requests.post(url, params=pulic_data, headers=header,data=json_data) # 正确的演示# --------------------获取响应数据---------------------------
print(res.json())
# print("响应的数据类型:", res.headers)# --------------------获取数据进行断言处理---------------------------
# 失败案例
exData = "登录成功"
# SjData = jsonpath.jsonpath(res.json(),"$.msg") # 错误的案例
SjData = jsonpath.jsonpath(res.json(),"$.msg")[0]
# print(SjData)
assert exData == SjData, "期望结构是:{0},实际结果是:{1}".format(exData, SjData)
示例2:
import requests
import jsonpath
import json
# 案例一:
url = "http://shop-xo.hctestedu.com/index.php?s=/api/user/login"
public_data = {"application": "app", "application_client_type": "weixin"}
data = {"accounts": "hami", "pwd": "123456", "type": "username"}
res = requests.post(url=url, params=public_data, data=data)
# ----------------------------------------
# 获取响应数据
result1 = res.json() # 以字典的格式获取
result2 = res.text # 以文本的格式获取
print(type(result1)) # 字典 <class 'dict'>
print(type(result2)) # 字符串 <class 'str'>
# 实际结果
# 字典格式:直接获取数据
# reality_res= jsonpath.jsonpath(result1, "$.msg")
# 字符串格式:先通过.loads()进行转换
dict_data = json.loads(result2)
reality_res = jsonpath.jsonpath(dict_data, "$.msg")
# 期望结果
desire_res = "登录成功"
# 断言:期望结果 == 实际结果
# assert desire_res == reality_res # 是一个列表需要通过下标获取具体的值
assert desire_res == reality_res[0]
print(reality_res)
接口关联 重要(上一个接口的响应数据作为下一个请求数据)
接口关联是在进行接口测试时,将一个接口的返回结果中的某些数据提取出来,然后作为后续接口请求的参数或者验证的依据。通过接口关联,可以实现接口间的数据传递和依赖关系的建立
接口关联通常分为两种类型:请求关联和响应关联。
1. 请求关联:
提取关键参数:在一个接口的请求中,某些参数的值是由之前接口的响应结果提供的。需要提取出这些关键参数,并将其作为后续接口的请求参数。
例如,一个接口的请求中需要使用到某个用户的登录令牌(token),可以通过在登录接口的响应结果中提取出令牌(token),然后在后续接口的请求中使用
2. 响应关联:
验证关键数据:在一个接口的响应结果中,某些数据是需要验证的,可以将这些数据提取出来,并进行断言或者其他验证操作。
例如,一个接口的响应结果中包含了某个订单的状态信息,可以将该状态信息提取出来,然后进行断言,验证订单是否处于正确的状态
1. 首先登录成功--提取token
2. 通过用户去进行加入购物车。--- token值取进行指定
在线美化json地址:JSON在线解析及格式化验证 - JSON.cn
案例:通过登录的用户把登录的用户加入购物车
import requests
import jsonpath
# 案例一:登录接口
url = "http://shop-xo.hctestedu.com/index.php?s=/api/user/login"
public_data = {"application": "app", "application_client_type": "weixin"}
data = {"accounts": "hami", "pwd": "123456", "type": "username"}
res = requests.post(url=url, params=public_data, data=data)
# ----------------------------------------
# 获取响应数据
result = res.json()
print(f"响应结果是:{result}")
# 期望结果
desire_res = "登录成功"
# 实际结果
reality_res = jsonpath.jsonpath(result, "$.msg")
# 断言:期望结果 == 实际结果
# assert desire_res == reality_res # 是一个列表需要通过下标获取具体的值
token = jsonpath.jsonpath(result, "$.data.token")
print(f"获取到的token值为:{token}")
assert desire_res == reality_res[0]
# 案例二:加入购物车
url = "http://shop-xo.hctestedu.com/index.php?s=/api/cart/save"
# public_data = {"application": "app", "application_client_type": "weixin", "token":
"8ae1ce79ed621a991a5e53ba9f96bfd3"}
public_data = {"application": "app", "application_client_type": "weixin", "token": token}
data = {
"goods_id": "11",
"spec": [
{
"type": "尺寸",
"value": "M"
}
],
"stock": "10"
} r
es = requests.post(url=url, params=public_data, data=data)
print(f"请求的url是:{res.url}")
# 获取响应数据
result = res.json()
print(f"响应结果是:{result}")
# 期望结果
desire_res = "加入成功"
# 实际结果
reality_res = jsonpath.jsonpath(result, "$.msg")
assert desire_res == reality_res[0]
对称加密与非对称加密
我们使用加密目的是提高数据的安全性
提高安全性的方法如下:
- 在对应的协议加认证证书: http请求 --- https请求 (花钱去买一个安全)
- 通过一些常用的算法去进行解决: MDH\ SHA\ 编码:BASE64
- 通过对应加密方式去进行加密:对称加密 、非对称加密
对称加密:
在对称加密算法中,加密和解密使用的是同一把钥匙,即:使用相同的密匙对 同一密码进行加密和解密
加密过程如下:
加密:原文 + 密匙 = 密文
解密:密文 - 密匙 = 原文
对称加密代码如下:
"""
对称加密:加密和解密使用的是同一把钥匙,即:使用相同的密匙对同一密码进行加密和解密。
常用的加密方法:DES、3DES、AES...(AES算法是目前最常用的对称加密算法)
"""
import base64
from Crypto.Cipher import AESclass EncryptDate:# 构造方法def __init__(self, key):# 类属性self.key = key.encode("utf-8") # 初始化密钥self.length = AES.block_size # 初始化数据块大小 :16位self.aes = AES.new(self.key, AES.MODE_ECB) # 初始化AES,ECB模式的实例# 截断函数,去除填充的字符self.unpad = lambda date: date[0:-ord(date[-1])]# 缺几位数据就补齐多少位数据:16的倍数def pad(self, text): # text == tony"""#填充函数,使被加密数据的字节码长度是block_size的整数倍"""count = len(text.encode('utf-8')) # count = 4add = self.length - (count % self.length) # 求它们相差的位数# add = 16- (4%16) === 16 - 4 == 12entext = text + (chr(add) * add)# entext = “tony” + (chr(add) * 12 ) === entext == tony# print("entext的数据是:",entext)return entext# 加密函数def encrypt(self, encrData): # 加密函数 encrData == tony (16位)res = self.aes.encrypt(self.pad(encrData).encode("utf8")) # self.aes.encrypt(tony)msg = str(base64.b64encode(res), encoding="utf8")return msg# 解密函数def decrypt(self, decrData): # 解密函数 XbXHJrNLwoTVcyfqM9eTgQ==# 从base64编码转回来res = base64.decodebytes(decrData.encode("utf8"))# 将数据进行对应的解密:XbXHJrNLwoTVcyfqM9eTgQ==msg = self.aes.decrypt(res).decode("utf8")# print("msg的值:",msg)# 把转回来的数据后面的字符去掉。return self.unpad(msg)def fun1():
# 通过方法把这个接口请求通passif __name__ == '__main__':# 加密 :会补位key = "1234567812345678" # key 密码data = "tony" # 数据eg = EncryptDate(key) # 这里密钥的长度必须是16的倍数,并且设置对应的【模式】res = eg.encrypt(str(data))print(f"加密后的数据为:{res}")# 解密 : 把后面的数据进行去除key = "1234567812345678" # key 密码data = "XbXHJrNLwoTVcyfqM9eTgQ==" # 数据eg = EncryptDate(key) # 这里密钥的长度必须是16的倍数res = eg.decrypt(str(data))print(f"解密后的数据为:{res}")
非对称加密:
明白了对称加密后,我们来了解一下什么是非对称加密。我们知道,对称加密是使用的同一把密匙进行加密和解密。那么,非对称加密自然是使用 不同的密钥进行加密和解密 啦。
非对称加密有两个钥匙,及公钥(Public Key)和私钥(Private Key)。公钥和私钥是成对的存在,如果对 原文 使用 公钥加密 ,则只能使用 对应的私钥 才能 解密 ;因为加密和解密使用的不是同一把密钥,所以这种算法称之为非对称加密算法。
非对称加密算法的密匙是通过一系列算法获取到的一长串随机数,通常随机数的长度越长,加密信息越安全。通过私钥经过一系列算法是可以推导出公钥的,也就是说,公钥是基于私钥而存在的。但是无法通过公钥反向推倒出私钥,这个过程是单向的
代码如下
# -*- coding: utf-8 -*-
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher# 注意开头
# PKCS1是BEGIN RSA PUBLIC KEY
# PKCS8是BEGIN PUBLIC KEY"""
PKCS8 案例"""
# 公钥
pub_str1 = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgFAOoAvLNvQv8BNGQq7B
m8ifMIUaYnFIC2Vu3ahW98zu/0Bg2GFAiIShOlNZcP8dGVLX6J4+p3k6pFRhloWJ
nviJUVU1xdZGjnk6snARB2V+8u73o5HQqn7ISgipjIb8pQc9wCZNBBT5eOB83K44
5Md0slkgz05jQ9Cj4UcIHUWquwGNQYo3zy9DOqDJaWimu46O1HnZAWrADsBfURPB
p9cqqmnxYMejqkBbj9JWhw+3YLpB9sLMQib0p7MEGA8GrpG+cXGYxdI0f0ZfJqEt
TpuJHNdSZwN7oZiBhJlL+tHOIRcq2dFCKUMYgrW9XK8cJVJVYxU7R1e2ZURXSmP3
yQIDAQAB
-----END PUBLIC KEY-----'''# 私钥
priv_str1 = '''-----BEGIN RSA PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCAUA6gC8s29C/w
E0ZCrsGbyJ8whRpicUgLZW7dqFb3zO7/QGDYYUCIhKE6U1lw/x0ZUtfonj6neTqk
VGGWhYme+IlRVTXF1kaOeTqycBEHZX7y7vejkdCqfshKCKmMhvylBz3AJk0EFPl4
4Hzcrjjkx3SyWSDPTmND0KPhRwgdRaq7AY1BijfPL0M6oMlpaKa7jo7UedkBasAO
wF9RE8Gn1yqqafFgx6OqQFuP0laHD7dgukH2wsxCJvSnswQYDwaukb5xcZjF0jR/
Rl8moS1Om4kc11JnA3uhmIGEmUv60c4hFyrZ0UIpQxiCtb1crxwlUlVjFTtHV7Zl
RFdKY/fJAgMBAAECggEALex5T47pDKIZBjPf0b36TWdgkl0RNGqW/n0vUOYPOmF+
qJzCDK/CCRpvGhD60hZ8s7OS0w7QHeClvGr3AoiI2PzbKOD2ffhTCGsbNwIlFiCd
bxVYTJLDvEHkLZssE7+8bNRKpZsPtYZMQ5cVGWbBtiAtBCgiNhA4Nu1VuitSHCdw
cpHrFCA7ESDmfmRGe7QAnTEkC2nUoM/9xPIBV4B1Lz3/KJuY+zJZWXkw1m64rC55
9cPILlc9zTrKYw0JSyC0PGXQSOZZ71TyEicsptVLIM2NT2ppdyu57i3IcVoFXyV6
XVoEWEFOXSppxkWXVXlYfJRT/rb1bEjzSCBWYKYGgQKBgQDLzcF1S/CMIlAW6LDY
vO0uoPOuMZE3yUUMASKrF2M0IuTZxO2Z/DSwwr3bt7X/r32sDceiVGAAj735VToh
ERhHOtgbP1s4S/rytHHMpAfEKciCcC8eNHvO4Q/N4W94B0uaUufamWRsgQog1F5F
12ymeuas0HApHTtEdohw1kR9uwKBgQChLMm5PyskU4ID0Jjse6XEwE4HcNCH9Qp6
MtBGznNLsGS2dLw8meKz6Q28ytgSGHPxFYEjzVmVKkiXzz95o6r3tn8so7IcfB+J
T55zn5DVK4o6ZYAeLWjBEzjTbbOIloFiOYgBHy9LXvV8kCN0bmBXvX1KEU2J6/Zh
rkIHRbZGSwKBgE0f+0MJTumpHofc3PfYXyWTMURNa7ghyahmUZlPi3IydkpW9Nee
Es6Fk9WvKwesgLF4sYCjz4TG4MyXTR0wW/CwuxFso3elgT0RvjMELBA3A7MhAyO6
FtROZW2zDzzr/ddT4nveKpvJJW0REO/7OxmxTtQ9OQTGFCSveqjA3UB7AoGBAJ4j
QbGehwfXX6O6kbDGCPmo7WZjjFc5WBRZsv0mJv3GjqpukxqqqkJ3keEA7Uuj7m5G
+TRVkWXH3P4GfHMu4Nq3lsQHwQQtzQt+sSslDof5dmChojj5uORnpcPcyOBlO4FS
jVz8afz7qMWU7xSYD7NG2p1HqNqASHfC8EoOXi9NAoGAZT5ezE1bTpIo40wArVJG
TA4R59m9RugGIFQl2Tpqw9ACUTjVNBkNtCpLEYV9Fznwy1PxE2OW5zGgpwWPm63D
D4tH1xShy5jOm7MIF7afrYgPbIYXyIdFtXY7sJuLETD2sYFBHG5ocZ4Pto/ELV7g
iK3ec+5UKwA/TN7l7Q7NE9A=
-----END RSA PRIVATE KEY-----
'''class Rsa:# 自动调用我们构造方法加载对应的公钥和私钥def __init__(self):# 加载公钥self.pub_key = RSA.importKey(pub_str1)# 加载私钥self.pri_Key = RSA.importKey(priv_str1)# rsa加密,返回加密结果def encrypt(self, text):# 1. 创建一个加密器对象 cipher,使用 self.pub_key 作为公钥cipher = PKCS1_cipher.new(self.pub_key)# 2. 加密:将text.encode("utf-8)" 转为b64编码rsa_text = base64.b64encode(cipher.encrypt(text.encode("utf-8)")))# 3. 解码为字符串text = rsa_text.decode("utf8")return text# rsa解密 返回解密结果def decrypt(self, text):# 1. 创建一个加密器对象 cipher,使用self.pri_Key作为公钥cipher = PKCS1_cipher.new(self.pri_Key)# 2. 解密:将密文数据 text 转换为 UTF-8 编码的字节序列,# 然后使用cipher对象调用decrypt()方法进行解密。# 解密前,还需要对密文进行 Base64 解码,得到原始的加密结果。# 第二个参数 0 表示不使用任何的填充方式rsa_text = cipher.decrypt(base64.b64decode(text.encode("utf8")), 0)# 解码为字符串text = rsa_text.decode("utf8")return textif __name__ == "__main__":# 1. 实例化对象rsaer = Rsa()# 2. 进行加密处理info = rsaer.encrypt('哈米')print('加密:', info)# 3. 进行解密处理print('解密:', rsaer.decrypt(info))