接口自动化框架搭建
Posted huaerye
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了接口自动化框架搭建相关的知识,希望对你有一定的参考价值。
使用requests库封装接口请求
详细教程请查看官方文档:https://requests.kennethreitz.org//zh_CN/latest/user/quickstart.html#url
入门教程:https://www.cnblogs.com/huaerye/p/9132607.html
参考文档:https://www.cnblogs.com/shapeL/p/9045439.html
第一次修改:将get请求和post请求单独定义,使用过程中根据不同类型的请求直接调用对应的方法;
def send_get(url,data,headers): res = requests.get(url=url,json=data,headers=headers).json() # return json.dumps(res,sort_keys=True,indent=2) return res def send_post(url,data,headers): res = requests.post(url=url,json=data,headers=headers).json() return json.dumps(res,sort_keys=True,indent=4) #indent默认情况下为空,4个空格,sort_keys:按照一定顺序展示数据 def run_main(url,headers,method,data=None): res =None if method == ‘GET‘: res = send_get(url,data,headers) else: res = send_post(url,data,headers) return res if __name__==‘__main__‘: url = ‘https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist‘ headers = { ‘token‘: "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g", ‘Content-Type‘: "application/json", } # 数据 data = {"stuNum":"795571161","page":1,"size": 5,"type":0} #url = ‘https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285‘ print(send_post(url,data,headers))
第二次修改:用class进行封装,主函数中创建一个实例run来调用类中的方法
import requests import json class Runmain(): def send_get(self,url,data,headers): res = requests.get(url=url,json=data,headers=headers).json() # return json.dumps(res,sort_keys=True,indent=2) return res def send_post(self,url,data,headers): res = requests.post(url=url,json=data,headers=headers).json() return json.dumps(res,sort_keys=True,indent=4) #indent默认情况下为空,4个空格,sort_keys:按照一定顺序展示数据 def run_main(self,url,headers,method,data=None): res =None if method == ‘GET‘: res = self.send_get(url,data,headers) else: res = self.send_post(url,data,headers) return res if __name__==‘__main__‘: run = Runmain url = ‘https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist‘ headers = { ‘token‘: "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g", ‘Content-Type‘: "application/json", } # 数据 data = {"stuNum":"795571161","page":1,"size": 5,"type":0} #url = ‘https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285‘ print(run.run_main(url,data,headers))
第三次修改:第二次修改,每次都需要实例化后再调用对应的方法;
改进办法:使用__init__
方法实现:只要实例化类时候就会调用__init__方法
import requests import json class Runmain(): def __init__(self,url,headers,method,data=None): self.res = self.run_main(url,headers,method,data) def send_get(self,url,data,headers): res = requests.get(url=url,json=data,headers=headers).json() # return json.dumps(res,sort_keys=True,indent=2) return res def send_post(self,url,data,headers): res = requests.post(url=url,json=data,headers=headers).json() return json.dumps(res,sort_keys=True,indent=4) #indent默认情况下为空,4个空格,sort_keys:按照一定顺序展示数据 def run_main(self,url,headers,method,data=None): res =None if method == ‘GET‘: res = self.send_get(url,data,headers) else: res = self.send_post(url,data,headers) return res if __name__==‘__main__‘: url = ‘https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist‘ headers = { ‘token‘: "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g", ‘Content-Type‘: "application/json", } # 数据 data = {"stuNum":"795571161","page":1,"size": 5,"type":0} #url = ‘https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285‘ run = Runmain(url,headers,data,‘post‘) print(run.res)
最后修改后的文件:将形参写到构造方法中,params=None,data=None,需要时可以传入参数;
demo.py使用requests get以及post方法进行了封装,主要是根据传递的参数method来对get以及post方法进行分别调用
import requests import json class Runmain(): def __init__(self,url,headers,method,params=None,data=None): self._url=url self._params = params self._data = data self._headers = headers self._method = method def send_get(self,url,params,headers): res = requests.get(url=url,params=params,headers=headers).json() #return json.dumps(res,sort_keys=True,indent=2) return res def send_post(self,url,data,headers): res = requests.post(url=url,json=data,headers=headers).json() return json.dumps(res,sort_keys=True,indent=4) def run_main(self): if self._method == ‘GET‘: return self.send_get(self._url,self._params,self._headers) else: return self.send_post(self._url,self._data,self._headers) if __name__==‘__main__‘: url = ‘https://oapi.t.blingabc.com/bms/admin-api/studentPreview/v1/myPreviews‘ headers = { ‘token‘: "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMzMDY5NiwiaWF0IjoxNTczNzI1ODk2fQ.yWaCaeOzZfVGokA7D7wrGeItcKPeyuythWIU52_1-rqZ9vEpYWRl6EYmq5thebccD0SecVpu6qLZm3NZu9DIqQ", ‘Content-Type‘: "application/json", #‘user-agent‘: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36" } # 数据 data = {"stuNum":"955163171","page":1,"size":5,"type":2} # url = ‘https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285‘ run = Runmain(url,headers,‘post‘,data).run_main() print(run)
unittest测试框架使用
详细用法请参考:https://www.cnblogs.com/huaerye/p/9361892.html
在test_method.py文件中则创建测试类以及test方法,在test方法中调用demo.py中的run_main方法,即使用requests模块向传递的接口url地址和请求方式以及请求体发送对应的请求,这里使用setUp方法则是利用其优先调用而对RunMain类进行实例化
import unittest from demo import Runmain class TestMethod(unittest.TestCase): def test_01(self): url = ‘https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285‘ headers = { ‘token‘: "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g", ‘Content-Type‘: "application/json", } res1 = Runmain(url,headers,‘GET‘).run_main() self.assertEqual(res1[‘code‘],10000,"测试通过") #添加断言 print(res1) def test_02(self): url = ‘https://oapi.blingabc.com/cms/user-api/student/homework/v2/homeworklist‘ headers = { ‘token‘: "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMxNzY2NSwiaWF0IjoxNTczNzEyODY1fQ.UjNSQSQpP6umRubppSggYB1W-dkmnfBB5RMNRQUTS9a8IJDmURyPT1bMIWg5nwHL1z7GvvJ-Ch5PKGLEnwOh6g", ‘Content-Type‘: "application/json", } data = {"stuNum":"795571161","page":1,"size": 5,"type":0} res2 = Runmain(url,headers,‘post‘,data).run_main() self.assertEqual(res2[‘code‘],10000,"测试通过") print(res2) if __name__==‘__main__‘: unittest.main() #3、还可以将要测试的case添加到unittest.TestSuite集合中执行想要执行的case,若想要全部都执行则需要一个一个的添加 # suite = unittest.TestSuite() # suite.addTest(TestMethod("test_01"))
数据依赖
设计一个接口自动化测试框架
根据接口地址丶接口类型丶请求数据丶预期结果来进行设计,对于需要登录后才能进行操作的接口那么则需要进行header cookie等数据的传递,自动化测试的难点就是数据依赖。
python操作excel获得内容
python操作excel,需要安装两个包,分别是xlrd和xlwt这两个库,xlrd这个库是负责读取excel数据的,而xlwt库是负责向excel写入数据的;
安装方式:pip3 install xlrd
项目目录下创建utils工具包,在该包下创建operation_excel.py文件,在该文件中通过导入xlrd包,对excel表的数据进行读取操作
重构操作excel函数
根据上一步骤读取excel表的内容代码后,进行了一个简单的封装,提高代码的通用性,实现代码如下:
import xlrd data = xlrd.open_workbook(‘../case/interface.xls‘) tables = data.sheets()[0] #获取表格数据对象 print(tables.nrows) #打印表格行数 print(tables.cell_value(1,2)) #打印excel表格数据,需要传递所在坐标(x,y) print("*"*50+"封装前后数据对比"+"*"*50) class OperationExcel(): def __init__(self,file_name=None,sheet_id=None): if file_name: self.file_name = file_name self.sheet_id = sheet_id else: self.file_name=‘../case/interface.xls‘ self.sheet_id = 0 self.data = self.get_data() #获取sheets的内容 def get_data(self): data = xlrd.open_workbook(self.file_name) tables = data.sheets()[self.sheet_id] return tables #获取单元格的行数 def get_lines(self): tables = self.data return tables.nrows #获取某一个单元格的内容 def get_cell_value(self,row,col): tables = self.data cell = tables.cell_value(row,col) return cell if __name__==‘__main__‘: opers = OperationExcel() print(opers.get_data().nrows) print(opers.get_lines()) print(opers.get_cell_value(1,2))
结果对比:
学习操作json文件
如果把请求数据全部放到excel里面,数据量大时,看起来不是很美观,所以将请求数据单独弄成一个json文件,将入参名传入excel就可以了;
在项目下新建一个dataconfig文件用于存json文件,在该文件下创建student.json,文件内容如下:
在utils工具包下创建operation_json.py文件,在文件中对login.json文件内容进行读取操作,以及重构json代码:
import json fp = open(‘../dataconfig/student.json‘) res = json.load(fp) #加载某个文件 print(res) print(res[‘student_login‘]) print(res[‘student_login‘][‘mobile‘]) print("="*50+"封装前后数据对比"+"="*50) class OperationJson(): def __init__(self, file_path="../dataconfig/student.json"): self.file_path = file_path self.data = self.get_data() def get_data(self): with open(self.file_path) as f: data = json.load(f) return data def get_key_words(self,key=None): if key: return self.data[key] else: return self.data if __name__==‘__main__‘: opjson = OperationJson() print(opjson.get_key_words()) print(opjson.get_key_words(‘student_login‘)) print(opjson.get_key_words(‘student_login‘)[‘mobile‘])
数据结果对比如下图:
封装获取常量方法
首先打开excel表格,查看需要获取的字段有哪些
对excel表的字段进行获取,在项目目录下创建名为data的python包,在该包下创建data_conf.py,代码就是简单的获取对应的变量值,具体如下
class global_var(): id = ‘0‘ # id description = ‘1‘ # 接口描述 url = ‘2‘ # 接口地址 run = ‘3‘ # 是否运行 request_way = ‘4‘ # 请求方式 request_header = ‘5‘ #是否携带header case_depend = ‘6‘ # case依赖 response_data_depend = ‘7‘ # 依赖的返回数据 data_depend = ‘8‘ # 数据依赖 request_data = ‘9‘ # 请求数据 expect_result = ‘10‘ # 预期结果 reality_result = ‘11‘ # 实际结果 def get_id(): return global_var.id def get_description(): return global_var.description def get_url(): return global_var.url def get_run(): return global_var.run def get_request_way(): return global_var.request_way def get_request_header(): return global_var.request_header def get_case_depend(): return global_var.case_depend def get_response_data_depend(): return global_var.response_data_depend def get_data_depend(): return global_var.data_depend def get_request_data(): return global_var.request_data def get_expect_result(): return global_var.expect_result def get_reality_result(): return global_var.reality_result
封装获取接口数据
在data目录下创建get_data.py文件,在该文件中对excel表数据以及json数据结合上一步封装的常量方法整合后的实现,代码如下
from util.operation_excel import OperationExcel from util.operation_json import OperationJson from data import data_config class GetData(): def __init__(self): self.op_excel = OperationExcel() def get_case_lines(self): """获取表格行数""" return self.op_excel.get_lines() def get_is_run(self,row): """获取case是否运行""" flag = None col = int(data_config.get_run()) run_model = self.op_excel.get_cell_value(row.col) if run_model == ‘yes‘: flag = True else: flag = False return flag def get_is_header(self,row): """是否携带header""" col = data_config.get_request_header() header = self.op_excel.get_cell_value(row,col) if header != ‘yes‘: return data_config.get_request_header() else: return None def get_request_method(self,row): """获取请求方式""" col = data_config.get_request_way() request_method = self.op_excel.get_cell_value(row,col) return request_method def get_request_url(self,row): """获取url地址""" col = data_config.get_url() url = self.op_excel.get_cell_value(row,col) return url def get_request_data(self,row): """获取请求数据""" col = data_config.get_url() request_data = self.op_excel.get_cell_value(row,col) if request_data == ‘‘: return None return request_data def get_header_value(self, row): """通过excel中的关键字去获取json数据""" op_json = OperationJson() data = op_json.get_key_words(self.get_request_data(row)) return data def get_expect_data(self,row): """获取预期结果数据""" col = data_config.get_expect_result() expect_data = self.op_excel.get_cell_value(row,col) if expect_data == ‘‘: return True return expect_data
post、get基类的封装
在util文件下新创建了run_method.py文件,将开始的demo文件复制了过来,其他未作改动,headers默认参数设置为了None,用时可传入headers参数;
import requests import json class Runmain(): def __init__(self,url,method,headers=None,params=None,data=None): self._url = url self._params = params self._data = data self._headers = headers self._method = method def send_get(self,url,params,headers): res = requests.get(url=url,params=params,headers=headers).json() #return json.dumps(res,sort_keys=True,indent=2) return res def send_post(self,url,data,headers): res = requests.post(url=url,json=data,headers=headers).json() return json.dumps(res,sort_keys=True,indent=4) def run_main(self): if self._method == ‘GET‘: return self.send_get(self._url,self._params,self._headers) else: return self.send_post(self._url,self._data,self._headers) if __name__==‘__main__‘: url = ‘https://oapi.t.blingabc.com/bms/admin-api/studentPreview/v1/myPreviews‘ headers = { ‘token‘: "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjb20ueGRmLmJsaW5nIiwiYXVkIjoiY2xpZW50IiwidXNlcmNvZGUiOiI5NTUxNjMxNyIsImV4cCI6MTU3NDMzMDY5NiwiaWF0IjoxNTczNzI1ODk2fQ.yWaCaeOzZfVGokA7D7wrGeItcKPeyuythWIU52_1-rqZ9vEpYWRl6EYmq5thebccD0SecVpu6qLZm3NZu9DIqQ", ‘Content-Type‘: "application/json", ‘user-agent‘: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36" } data = {"stuNum":"955163171","page":1,"size":5,"type":2} # url = ‘https://oapi.t.blingabc.com/bms/admin-api/specialsubject/v1/save-phonics?id=285‘ run = Runmain(url,‘post‘,headers,data).run_main() print(run)
主流程封装及错误解决调试
以上是关于接口自动化框架搭建的主要内容,如果未能解决你的问题,请参考以下文章
API接口自动化测试框架搭建(二十六)-框架README.md设计
API接口自动化测试框架搭建-封装conf配置文件读写数据方法operate_conf.py