本文所用项目来源于白月黑羽的白月SMS系统:Bysms 系统安装与运行 | 白月黑羽
仅用于框架搭建练习与回顾,不做其他性质操作。
如有僭越侵权,麻烦您私信联系删除。
框架基于 python + requests + unittest + ddt
大致流程:从excel表格中拿数据,进行发送请求,对响应结果进行断言,将结果写入excel中。
(事实上断言可以做数据库断言,这里不做设计)
from openpyxl import load_workbook
class ToolsExecl:
def __init__(self,FileName):
self.workbook = load_workbook(filename=FileName)
# 实例化对象
setattr(self,'FileName',FileName)
# 将文件名字设置为类属性
def open_execl(self, SheetName=None):
# 从表格中读取数据
try:
if SheetName:
sheet = self.workbook[SheetName]
datas = list(sheet.iter_rows(values_only=True))
data_list = []
case_title = datas[0]
case_datas = datas[1:]
for case in case_datas:
result = dict(zip(case_title, case))
data_list.append(result)
return data_list
# 返回一个数据列表,内在元素为key:value
except Exception as e:
print(f"读取{SheetName}表有误", e)
finally:
self.close_execl()
def write_execl(self,SheetName, case_id, Text=None):
# 将需要的内容写入excel中
try:
sheet = self.workbook[SheetName]
datas = list(sheet.iter_rows(values_only=True))[0]
datas = list(enumerate(datas, start=1))
for data in datas:
if data[1] == 'result':
setattr(ToolsExecl, 'column', int(data[0]))
sheet.cell(row=int(case_id + 1), column=getattr(ToolsExecl, 'column'), value=Text)
self.workbook.save(filename=getattr(self,'FileName'))
print(sheet.max_row)
except Exception as e:
print("读取数据有误", e)
finally:
self.close_execl()
def close_execl(self):
# 关闭表格
self.workbook.close()
if __name__ == '__main__':
pass
Request URL: http://127.0.0.1/api/mgr/signin Request Method: POST Content-Type: application/x-www-form-urlencoded; charset=UTF-8 username: byhy password: 88888888
在excel表格中设计用例,填入以上请求必须项
(请求头可以单独设置,也可以不设置,这里只有这一个form表单请求所以不做单独设置。)
用例首行id编号,title标题,method请求方法,url请求地址,data请求参数,expect预期结果,result写入结果,作为数据提取字段传递参数;
用例只是简单举例设计,可以更加完善(如少参多参,有效无效参数)。
1.读取数据(通过封装好的ToolsExecl类读取数据)
2.发送请求(将需要的请求单独封装一个类,方便添加/减少参数)
3.对实际响应结果和预期结果做断言(封装一个类用于对结果断言)
4.通过写入结果pass,失败写入fail (ToolsExecl类中的write_execl)
发送请求封装一个类:发送请求方法
import requests
class ToolsRequest:
def __init__(self):
self.head = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
def send_request(self, method, url, data):
resq = requests.request(method=method, url=url, data=data, headers=self.head)
return resq
# 返回一个对象,后续需要什么数据,可操作性大
响应结果处理,进行断言,写入数据对应ToolsExecl类中的write_execl方法
import json
from jsonpath import jsonpath
from TestTools.Tools_Execl import ToolsExecl
class ToolsRespone:
def __init__(self,FileName):
self.ToolsExecl=ToolsExecl(FileName=FileName)
def tool_response(self, response):
# 将结果包装成统一的格式
try:
if isinstance(response.json(), dict):
return {"response": response.json()}
except Exception as e:
return {"response": response.text}
def assert_response(self, response, expect, SheetName, case_id):
response = self.tool_response(response=response)
if expect:
actual = {}
expect = expect if isinstance(expect, dict) else json.loads(expect)
for key in expect:
actual[key] = jsonpath(response, f"$..{key}")[0]
try:
assert actual == expect
self.ToolsExecl.write_execl(SheetName=SheetName, case_id=case_id, Text="pass")
except Exception as e:
self.ToolsExecl.write_execl(SheetName=SheetName, case_id=case_id, Text="fail")
框架执行代码就可以写成以下格式:
"""
代码执行处
"""
import unittest
from ddt import ddt,data
from TestTools.Tools_Execl import ToolsExecl
from TestTools.Tools_Requests import ToolsRequest
from TestTools.Tools_Respone import ToolsRespone
data_list = ToolsExecl(FileName=testdata_path).open_execl( SheetName="login")
# testdata_path 为自己放置excel表格的地址
@ddt
class TestSMS(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.ToolsRequest = ToolsRequest()
cls.ToolExtract = ToolExtract()
cls.ToolsRespone = ToolsRespone(FileName=testdata_path)
@data(*data_list)
def testmethod(self, case):
# 发送请求
resq = self.ToolsRequest.send_request(method=case['method'], url=case['url'], data=case['data'])
# 断言响应,并写入结果
self.ToolsRespone.assert_response(response=resq, expect=case['expect'],
SheetName="login", case_id=case['id'])
if __name__ == '__main__':
unittest.main()
运行成功后可以看到excel表中result列写入了pass
用例设计:
(简单设置用例,在有效无效/少惨多参/边界可以做文章)
# 添加客户 Request URL: http://127.0.0.1/api/mgr/customers Request Method: POST Content-Type: application/json Cookie: sessionid=ygyhv302ke1gnncoghjzy8lkqw81g93x 接口响应:{"id":23,"ret":0}# 修改客户 Request URL: http://127.0.0.1/api/mgr/customers Request Method: PUT Content-Type: application/json Cookie: sessionid=ygyhv302ke1gnncoghjzy8lkqw81g93x 接口响应:{"ret":0}# 删除客户
Request URL: http://127.0.0.1/api/mgr/customers Request Method: DELETE Content-Type: application/json Cookie: sessionid=ygyhv302ke1gnncoghjzy8lkqw81g93x 响应:{"ret":0}
流程:先登录-保存cookie或token信息-后面请求接口带上请求头操作即可
保存cookie或者token新增一个类来实现,excel中也需要新增一列提取列 extract。
新增一个类ToolsAttribute,用于保存变量。
class ToolsAttribute:
pass
import json
from jsonpath import jsonpath
from TestTools.Tools_Attribute import ToolsAttribute
class ToolExtract:
# 提取cookie信息
def extract_data(self, extract: str, response):
# 从excel中来的数据均为str格式,response为响应对象,未做任何处理的对象
if extract:
extract = extract if isinstance(extract, dict) else json.loads(extract)
for k, v in extract.items():
if k == 'Set-Cookie':
value = response.headers[k]
setattr(ToolsAttribute, k, str(value))
else:
value = jsonpath(response.json(), f"$..{k}")[0]
setattr(ToolsAttribute, k, value)
需要注意的细节:
1.只有登录的时候请求头为form,后续的数据请求头均为json,所以需要在请求头上进行修改;
2.添加成功后的相应信息{"id":23,"ret":0},其中id的value为int类型
最终流程为:
登录,提取cookie/token保存到请求头
添加客户,加上请求头,data转为对应类型,提取添加成功后的id信息
修改客户,加上请求头,替换data里的id
删除客户,加上请求头,替换data里的id
"""
请求代码示例
"""
import json
import requests
from TestTools.Tools_Attribute import ToolsAttribute
class ToolsRequest:
def __init__(self):
self.head = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
self.fk = Faker(locale="zh-CN")
def __headers(self):
if hasattr(ToolsAttribute, 'Set-Cookie'):
# 处理请求头
cookie = getattr(ToolsAttribute, 'Set-Cookie')
headers = {"Content-Type": "application/json"}
if 'cookie' not in self.head.keys():
# 判断请求头中是否存在token
headers['Cookie'] = cookie
setattr(ToolsAttribute, 'cookie_head', headers)
else:
print('已有cookie,不需要再次设置请求头')
def data_replace(self, data: str):
if data:
data = json.loads(data)
for key, value in data.items():
if key == "id":
data[key] = getattr(ToolsAttribute, key)
return data
else:
print("data不存在,无需替换")
return {}
def send_request(self, method, url, data):
self.__headers()
data = self.data_replace(data=data)
if "action" not in data.keys():
resq = requests.request(method=method, url=url, data=data, headers=self.head)
else:
resq = requests.request(method=method, url=url, json=data, headers=getattr(ToolsAttribute, 'cookie_head'))
return resq
代码基本成型,只需要完善细节和diy设计即可
后续的订单和药品接口也同理,只需在新增excel中新增对应表和数据即可。
这个简陋版的框架有许多的细节可以添加,如:请求头的设置,url的拆分,添加商品后对查询数据库进行断言,生成随机数据进行替换等,可以在此思路上逐渐发挥,完善代码
本文所用项目来源于白月黑羽的白月SMS系统:Bysms 系统安装与运行 | 白月黑羽
仅用于框架搭建练习与回顾,不做其他性质操作。
如有僭越侵权,麻烦您私信联系删除。