在编写接口测试脚本时,要考虑一个问题:参数值从哪里获取
一种方式是可以通过数据库来获取,但是通过这次接口测试,我发现读取数据库有一个缺点:速度慢
可能和我的sql写法有关,有些sql加的约束条件比较少,有时甚至全量查询,把所有结果遍历一遍,这样一轮下来直接就炸了,那速度比蜗牛还慢
这种方式给我的体验不太好,一方面本身连数据库这个操作我就不太愿意用,生怕对数据库造成什么伤害......
另一种方式就是写死参数,不过除非是一些固定的参数,比如按照某个类型查询,类型是固定的,那么可以事先定义一个列表或字典存放类型值,然后依次遍历即可;
否则一般不推荐写死参数,写死的话拓展性不强,换个测试环境,脚本可能就运行不起来了
还有就是通过接口获取想要的数据了,也就是一个接口能返回某些参数想要的值,那么就把这个接口的返回值传递给下个接口的参数
这样一来,参数值是动态生成的,即使切换环境,也可以在新环境获取参数值,然后再去发送请求
本质上接口间传递参数,其实就是处理上一个接口的返回数据,抽取出自己想要的某个字段或某一批字段
举个栗子:
有2个接口,A接口用于查询所有的标签数据,B接口需要传入一个标签,然后生成一条草稿数据
这样的话,可以在A接口查询出的所有标签中选择一个传给B
A接口的返回数据如下:seq表示标签编码,B接口本质上就是需要一条标签编码来生成数据
labelStatus表示标签状态,0表示启用,1表示未启用
代码语言:javascript复制{
'total': '5',
'rows': [{
'seq': '151ceb6c0e624537a2b067d511c4c966',
'labelCode': '004',
'labelName': '拼多多',
'labelStatus': 0,
'kseq': None,
'lseq': None
}, {
'seq': '1aa2ddfe896848cf893eebe6c37a79e6',
'labelCode': '002',
'labelName': '京东',
'labelStatus': 0,
'kseq': None,
'lseq': None
}, {
'seq': '25879c28e8b54bf0b75168fc60c31a91',
'labelCode': '001',
'labelName': '天猫',
'labelStatus': 0,
'kseq': None,
'lseq': None
}, {
'seq': '7715e67a153d484996a07af19ef33c09',
'labelCode': '003',
'labelName': '苏宁',
'labelStatus': 0,
'kseq': None,
'lseq': None
}, {
'seq': '647733588fa34f60858e42ccd7357975',
'labelCode': '005',
'labelName': '唯品会',
'labelStatus': 1,
'kseq': None,
'lseq': None
}]
}
先写一个方法,提取查询到的标签编码
代码语言:javascript复制def get_all_label(self):
"""获取菜单中所有标签数据"""
url = "http://127.0.0.1:8080/XXX"
payload = {
"page": "1",
"rows": "10",
"sort": "labelStatus",
"order": "asc"
}
response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False)
data = json.loads(response.content)
# print(data)
try:
self.assertIn("rows", data)
self.assertIn("total", data)
if data["rows"]:
labels = [] # 定义一个列表存查询到的所有标签数据
for t in data["rows"]:
"""以列表中嵌套字典的格式保存,易于调用"""
if t["labelStatus"] == 0:
"""如果labelStatus为0则追加到列表中"""
labels.append(
{"seq": t["seq"],
"labelCode": t["labelCode"],
"labelName": t["labelName"],
"labelStatus": t["labelStatus"]}
)
# print(labels)
return labels
else:
labels = None
return labels
except Exception as e:
print("请求url:", response.url)
print("传入参数:", payload)
raise e
B接口用于创建草稿数据,参数中用到A接口返回的标签编码seq;
创建一个生成草稿数据的方法,在这个方法中,定义一个变量seq,用于接收标签编码
代码语言:javascript复制def add_draft(self, seq=None):
"""新增草稿"""
url = "http://127.0.0.1:8080/XXX"
payload = {
"title": "XX",
"applyType": 0,
"hotFlag": 1,
"content": "XX",
"replyContent": "XX",
"labelList[0].lseq": seq, # 接收传入的seq
"faqList[0].content": "XX",
"faqList[0].replyContent": "XX",
"fnType": 0
}
response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False)
data = response.json()
# print(data)
try:
self.assertEqual(data["success"], "true")
self.assertEqual(data["successful"], True)return data
except Exception as e:
print("请求url:", response.url)
print("传入参数:", payload)
raise e
最后利用上面2个方法编写一条用例
代码语言:javascript复制def test01(self):
try:
labels = self.get_all_label() # 调用查询标签方法,获取所有可用标签
# n = isinstance(labels, Iterable)
# print(n)
if labels:
label = random.choice(labels) # 从获取到的标签列表中随机取出一个
seq = label["seq"] # 从取出的一个标签中,获取其seq值
data = self.add_draft(seq) # 调用生成草稿数据方法,并将seq传入
print("使用的标签名:{},对应的标签seq:{},返回的草稿编码:{}".format(label["labelName"], label["seq"], data["data"]))
elif labels is None:
print("标签菜单暂无可用数据,请先去添加标签")
except Exception as e:
print("错误详情:", e)
raise e
在实际编写过程中,由于每个接口的实际情况不同,所以要做相应的处理,例如
1. 在获取标签过程中,只有启用状态的标签才能使用,所以需要判断下标签的状态;
2. 需要考虑下假如标签菜单为空怎么办?这个时候获取标签的方法就拿不到数据,所以也要加个判断,没有标签数据时,这个方法要返回什么内容,以及后续接口做相应处理,避免当接收不到seq时报异常;
3. 另外就是有些接口在开发时定义的不是很规范,虽然返回的一大批数据,但是有些数据可能少个字段,例如上述获取标签接口的某些返回内容中缺少seq,那在提取每一组的seq时,就要判断seq这个字段是不是存在,存在则提取,不存在则略过。
其实这些问题也是在实际运行过程中发现的缺陷,很多异常情况没有考虑到,脚本不是写完就完了的,还要放到环境中运行,只有这样才会发现脚本不完善的地方。
这只是一个简单例子,实际情况可能更复杂一些,例如需要返回多个参数的情况或者把多个接口的返回值传递给一个接口等等;
不过道理都是一样的,要学会分析接口返回内容的结构,提取自己想要的值。更多细节以及技巧等待大家在实际使用过程中发现
完整demo:
login.py,使用cookie跳过验证码登录,可以参考:https://www.cnblogs.com/hanmk/p/9101275.html
代码语言:javascript复制# coding:utf-8
import requests
# from requests.cookies import RequestsCookieJar
class Login:
@staticmethod
def test_login():
s = requests.session()
jar = requests.cookies.RequestsCookieJar() # 创建一个Cookie Jar对象
jar.set('XXX', 'xxx') # 向Cookie Jar对象中添加cookie值
jar.set('XXX', 'xxx')
jar.set('XXX', 'xxx')
s.cookies.update(jar) # 把cookies追加到Session中
return s
test.py
代码语言:javascript复制# coding:utf-8
import unittest
from hmk.login import Login
import warnings
import json
import random
from collections import Iterable
class ModuleList(unittest.TestCase):
def setUp(self):
warnings.simplefilter("ignore", ResourceWarning)
self.s = Login()
self.url = 'http://127.0.0.1:8080/XXX'
self.header = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "http://127.0.0.1:8080",
"Referer": "http://127.0.0.1:8080XXX",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
}
def get_all_label(self):
"""获取菜单中所有标签数据"""
url = "http://127.0.0.1:8080XXX"
payload = {
"page": "1",
"rows": "10",
"sort": "labelStatus",
"order": "asc"
}
response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False)
data = json.loads(response.content)
# print(data)
try:
self.assertIn("rows", data)
self.assertIn("total", data)
if data["rows"]:
labels = [] # 定义一个列表存查询到的所有标签数据
for t in data["rows"]:
"""以列表中嵌套字典的格式保存,易于调用"""
if t["labelStatus"] == 0:
"""如果labelStatus为0则追加到列表中"""
labels.append(
{"seq": t["seq"],
"labelCode": t["labelCode"],
"labelName": t["labelName"],
"labelStatus": t["labelStatus"]}
)
# print(labels)
return labels
else:
labels = None
return labels
except Exception as e:
print("请求url:", response.url)
print("传入参数:", payload)
raise e
def add_draft(self, seq=None):
"""新增草稿"""
url = "http://127.0.0.1:8080/XXX"
payload = {
"title": "XXX",
"applyType": 0,
"hotFlag": 1,
"content": "XXX",
"replyContent": "XXX",
"labelList[0].lseq": seq, # 接收传入的seq
"faqList[0].content": "XXX",
"faqList[0].replyContent": "XXX",
"fnType": 0
}
response = self.s.test_login().post(url, data=payload, headers=self.header, verify=False)
data = response.json()
# print(data)
try:
self.assertEqual(data["success"], "true")
self.assertEqual(data["successful"], True)return data
except Exception as e:
print("请求url:", response.url)
print("传入参数:", payload)
raise e
def test01(self):
try:
labels = self.get_all_label() # 调用查询标签方法,获取所有可用标签
# n = isinstance(labels, Iterable)
# print(n)
if labels:
label = random.choice(labels) # 从获取到的标签列表中随机取出一个
seq = label["seq"] # 从取出的一个标签中,获取其seq值
data = self.add_draft(seq) # 调用生成草稿数据方法,并将seq传入
print("使用的标签名:{},对应的标签seq:{},返回的草稿编码:{}".format(label["labelName"], label["seq"], data["data"]))
elif labels is None:
print("标签菜单暂无可用数据,请先去添加标签")
except Exception as e:
print("错误详情:", e)
raise e
if __name__ == '__main__':
# unittest.main()
suite = unittest.TestSuite()
suite.addTest(ModuleList('test01'))
runner = unittest.TextTestRunner()
runner.run(suite)