Python+requests+unittest+excel接口自动化测试框架

一、框架结构:

 工程目录

二、Case文件设计

三、基础包 base

3.1 封装get/post请求(runmethon.py)

 impimport jsonclass RunMethod:def post_main(self,url,data,header=None):res = Noneif header !=None: res = requests.post(url=url,data=data,headers=header)else:res = requests.post(url=url,data=data)return res.json()def get_main(self,url,data=None,header=None):res = Noneif header !=None: res = requests.get(url=url,data=data,headers=header,verify=False)else:res = requests.get(url=url,data=data,verify=False)return res.json() def run_main(self,method,url,data=None,header=None):res = Noneif method == 'Post':res = self.post_main(url,data,header)else:res = self.get_main(url,data,header)return json.dumps(res,ensure_ascii=False,sort_keys=True,indent=2)

3.2 封装mock(mock.py)

from mock import mock#模拟mock 封装def mock_test(mock_method,request_data,url,method,response_data):mock_method = mock.Mock(return_value=response_data)res = mock_method(url,method,request_data)return res

四、数据操作包 operation_data4.1 获取excel单元格中的内容(get_data.py)  

 
#coding:utf-8from tool.operation_excel import OperationExcelimport data_configfrom tool.operation_json import OperetionJsonfrom tool.connect_db import OperationMysqlclass GetData:def __init__(self):self.opera_excel = OperationExcel()#去获取excel行数,就是case的个数 def get_case_lines(self):return self.opera_excel.get_lines()#获取是否执行def get_is_run(self,row):flag = Nonecol = int(data_config.get_run())run_model = self.opera_excel.get_cell_value(row,col)if run_model == 'yes':flag = Trueelse:flag = False
return flag#是否携带header
def is_header(self,row):col = int(data_config.get_header())header = self.opera_excel.get_cell_value(row,col)if header != '':return headerelse:return None#获取请求方式def get_request_method(self,row):col = int(data_config.get_run_way())request_method = self.opera_excel.get_cell_value(row,col)return request_method#获取urldef get_request_url(self,row):col = int(data_config.get_url())url = self.opera_excel.get_cell_value(row,col)return url#获取请求数据def get_request_data(self,row):col = int(data_config.get_data())data = self.opera_excel.get_cell_value(row,col)if data == '':return Nonereturn data#通过获取关键字拿到data数据def get_data_for_json(self,row):opera_json = OperetionJson()request_data = opera_json.get_data(self.get_request_data(row))return request_data#获取预期结果def get_expcet_data(self,row):col = int(data_config.get_expect())expect = self.opera_excel.get_cell_value(row,col)if expect == '':return Nonereturn expect#通过sql获取预期结果def get_expcet_data_for_mysql(self,row):op_mysql = OperationMysql()sql = self.get_expcet_data(row)res = op_mysql.search_one(sql)return res.decode('unicode-escape')def write_result(self,row,value):col = int(data_config.get_result())self.opera_excel.write_value(row,col,value)#获取依赖数据的keydef get_depend_key(self,row):col = int(data_config.get_data_depend())depent_key = self.opera_excel.get_cell_value(row,col)if depent_key == "":return Noneelse:return depent_key#判断是否有case依赖def is_depend(self,row):col = int(data_config.get_case_depend())depend_case_id = self.opera_excel.get_cell_value(row,col)if depend_case_id == "":return Noneelse:return depend_case_id#获取数据依赖字段def get_depend_field(self,row):col = int(data_config.get_field_depend())data = self.opera_excel.get_cell_value(row,col)if data == "":return Noneelse:return data 

4.2 获取excel中每个列(data_config.py)

#coding:utf-8class global_var:#case_idId = '0'request_name = '1'url = '2'run = '3'request_way = '4'header = '5'case_depend = '6'data_depend = '7'field_depend = '8'data = '9'expect = '10'result = '11'#获取caseiddef get_id():return global_var.Id#获取urldef get_url():return global_var.urldef get_run():return global_var.rundef get_run_way():return global_var.request_waydef get_header():return global_var.headerdef get_case_depend():return global_var.case_dependdef get_data_depend():return global_var.data_dependdef get_field_depend():return global_var.field_dependdef get_data():return global_var.datadef get_expect():return global_var.expectdef get_result():return global_var.resultdef get_header_value():return global_var.header

4.3 解决数据依赖(dependent.py )

#coding:utf-8import sysimport jsonsys.path.append('C:/Users/lxz/Desktop/InterFace_JIA')from tool.operation_excel import OperationExcelfrom base.runmethod import RunMethodfrom operation_data.get_data import GetDatafrom jsonpath_rw import jsonpath,parseclass DependdentData:def __init__(self,case_id):self.case_id = case_idself.opera_excel = OperationExcel()self.data = GetData()#通过case_id去获取该case_id的整行数据def get_case_line_data(self):rows_data = self.opera_excel.get_rows_data(self.case_id)return rows_data#执行依赖测试,获取结果def run_dependent(self):run_method = RunMethod()row_num = self.opera_excel.get_row_num(self.case_id)request_data = self.data.get_data_for_json(row_num)#header = self.data.is_header(row_num)method = self.data.get_request_method(row_num)url = self.data.get_request_url(row_num)res = run_method.run_main(method,url,request_data)return json.loads(res)#根据依赖的key去获取执行依赖测试case的响应,然后返回def get_data_for_key(self,row):depend_data = self.data.get_depend_key(row)response_data = self.run_dependent()json_exe = parse(depend_data)madle = json_exe.find(response_data)return [math.value for math in madle][0]if __name__ == '__main__':order = {"data": {"_input_charset": "utf-8","body": "京东订单-1710141907182334","it_b_pay": "1d","notify_url": "http://order.imooc.com/pay/notifyalipay","out_trade_no": "1710141907182334","partner": "2088002966755334","payment_type": "1","seller_id": "yangyan01@tcl.com","service": "mobile.securitypay.pay","sign": "kZBV53KuiUf5HIrVLBCcBpWDg%2FnzO%2BtyEnBqgVYwwBtDU66Xk8VQUTbVOqDjrNymCupkVhlI%2BkFZq1jOr8C554KsZ7Gk7orC9dDbQlpr%2BaMmdjO30JBgjqjj4mmM%2Flphy9Xwr0Xrv46uSkDKdlQqLDdGAOP7YwOM2dSLyUQX%2Bo4%3D","sign_type": "RSA","string": "_input_charset=utf-8&body=京东订单-1710141907182334&it_b_pay=1d&notify_url=http://order.imooc.com/pay/notifyalipay&out_trade_no=1710141907182334&partner=2088002966755334&payment_type=1&seller_id=yangyan01@tcl.com&service=mobile.securitypay.pay&subject=京东订单-1710141907182334&total_fee=299&sign=kZBV53KuiUf5HIrVLBCcBpWDg%2FnzO%2BtyEnBqgVYwwBtDU66Xk8VQUTbVOqDjrNymCupkVhlI%2BkFZq1jOr8C554KsZ7Gk7orC9dDbQlpr%2BaMmdjO30JBgjqjj4mmM%2Flphy9Xwr0Xrv46uSkDKdlQqLDdGAOP7YwOM2dSLyUQX%2Bo4%3D&sign_type=RSA","subject": "京东订单-1710141907182334","total_fee": 299},"errorCode": 1000,"errorDesc": "成功","status": 1,"timestamp": 1507979239100}res = "data.out_trade_no"json_exe = parse(res)madle = json_exe.find(order)print [math.value for math in madle][0]

五、工具类包 tool5.1 操作excel (operation_excel.py)

 
#coding:utf-8import xlrdfrom xlutils.copy import copyclass OperationExcel:def __init__(self,file_name=None,sheet_id=None):if file_name:self.file_name = file_nameself.sheet_id = sheet_id else:self.file_name = '../dataconfig/case1.xls'self.sheet_id = 0self.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.datareturn tables.nrows#获取某一个单元格的内容def get_cell_value(self,row,col):return self.data.cell_value(row,col)#写入数据def write_value(self,row,col,value):'''写入excel数据row,col,value'''read_data = xlrd.open_workbook(self.file_name)write_data = copy(read_data)sheet_data = write_data.get_sheet(0)sheet_data.write(row,col,value)write_data.save(self.file_name)#根据对应的caseid 找到对应行的内容def get_rows_data(self,case_id):row_num = self.get_row_num(case_id)rows_data = self.get_row_values(row_num)return rows_data#根据对应的caseid找到对应的行号def get_row_num(self,case_id):num = 0clols_data = self.get_cols_data()for col_data in clols_data:if case_id in col_data:return numnum = num+1#根据行号,找到该行的内容def get_row_values(self,row):tables = self.datarow_data = tables.row_values(row)return row_data#获取某一列的内容def get_cols_data(self,col_id=None):if col_id != None:cols = self.data.col_values(col_id)else:cols = self.data.col_values(0)return colsif __name__ == '__main__':opers = OperationExcel()print opers.get_cell_value(1,2)

5.2判断字符串包含,判断字典是否相等(common_util.py)

 
#coding:utf-8import jsonclass CommonUtil:def is_contain(self,str_one,str_two):'''判断一个字符串是否再另外一个字符串中str_one:查找的字符串
str_two:被查找的字符串'''flag = Noneif isinstance(str_one,unicode):str_one = str_one.encode('unicode-escape').decode('string_escape')return cmp(str_one,str_two)if str_one in str_two:flag = Trueelse:flag = Falsereturn flagdef is_equal_dict(self,dict_one,dict_two):'''判断两个字典是否相等'''if isinstance(dict_one,str):dict_one = json.loads(dict_one)if isinstance(dict_two,str):dict_two = json.loads(dict_two)return cmp(dict_one,dict_two)

5.3 操作header(operation_herder.py)

 
#coding:utf-8import requestsimport jsonfrom operation_json import OperetionJsonclass OperationHeader: def __init__(self,response):self.response = json.loads(response)def get_response_url(self):'''获取登录返回的token的url'''url = self.response['data']['url'][0]return urldef get_cookie(self):'''获取cookie的jar文件'''url = self.get_response_url()+"&callback=jQuery21008240514814031887_1508666806688&_=1508666806689"cookie = requests.get(url).cookiesreturn cookiedef write_cookie(self):cookie = requests.utils.dict_from_cookiejar(self.get_cookie())op_json = OperetionJson()op_json.write_data(cookie)if __name__ == '__main__':url = "http://www.jd.com/passport/user/login"data = {"username":"18513199586","password":"111111","verify":"","referer":"https://www.jd.com"}res = json.dumps(requests.post(url,data).json())op_header = OperationHeader(res)op_header.write_cookie()

5.4 操作json文件(operation_json.py)

 #coding:utf-8import jsonclass OperetionJson:def __init__(self,file_path=None):if file_path == None:self.file_path = '../dataconfig/user.json'else:self.file_path = file_pathself.data = self.read_data()#读取json文件def read_data(self):with open(self.file_path) as fp:data = json.load(fp)return data#根据关键字获取数据def get_data(self,id):print type(self.data)return self.data[id]#写jsondef write_data(self,data):with open('../dataconfig/cookie.json','w') as fp:fp.write(json.dumps(data))if __name__ == '__main__':opjson = OperetionJson()print opjson.get_data('shop')

5.5 操作数据库(connect_db.py)

#coding:utf-8import MySQLdb.cursorsimport jsonclass OperationMysql:def __init__(self):self.conn = MySQLdb.connect(host='localhost',port=3306,user='root',passwd='123456',db='le_study',charset='utf8',cursorclass=MySQLdb.cursors.DictCursor
)self.cur = self.conn.cursor()#查询一条数据def search_one(self,sql):self.cur.execute(sql)result = self.cur.fetchone()result = json.dumps(result)return resultif __name__ == '__main__':op_mysql = OperationMysql()res = op_mysql.search_one("select * from web_user where Name='ailiailan'")print res

5.6 发送报告邮件(send_email.py)

#coding:utf-8
import smtplibfrom email.mime.text import MIMETextclass SendEmail:global send_userglobal email_hostglobal passwordemail_host = "smtp.163.com"send_user = "jiaxiaonan666@163.com"password = "jia_668"def send_mail(self,user_list,sub,content):user = "jiaxiaonan"+"<"+send_user+">"message = MIMEText(content,_subtype='plain',_charset='utf-8')message['Subject'] = submessage['From'] = usermessage['To'] = ";".join(user_list)server = smtplib.SMTP()server.connect(email_host)server.login(send_user,password)server.sendmail(user,user_list,message.as_string())server.close()def send_main(self,pass_list,fail_list):pass_num = float(len(pass_list))fail_num = float(len(fail_list))count_num = pass_num+fail_num#90%pass_result = "%.2f%%" %(pass_num/count_num*100)fail_result = "%.2f%%" %(fail_num/count_num*100)user_list = ['609037724@qq.com']sub = "接口自动化测试报告"content = "此次一共运行接口个数为%s个,通过个数为%s个,失败个数为%s,通过率为%s,失败率为%s" %(count_num,pass_num,fail_num,pass_result,fail_result )self.send_mail(user_list,sub,content)if __name__ == '__main__':sen = SendEmail()sen.send_main([1,2,3,4],[2,3,4,5,6,7]) 

六、主函数

run_test.py#coding:utf-8import syssys.path.append("C:/Users/lxz/Desktop/InterFace_JIA")from base.runmethod import RunMethodfrom operation_data.get_data import GetDatafrom tool.common_util import CommonUtilfrom operation_data.dependent_data import DependdentDatafrom tool.send_email import SendEmailfrom tool.operation_header import OperationHeaderfrom tool.operation_json import OperetionJsonclass RunTest:def __init__(self):self.run_method = RunMethod()self.data = GetData()self.com_util = CommonUtil()self.send_mai = SendEmail()#程序执行的def go_on_run(self):res = Nonepass_count = []fail_count = []#10 0,1,2,3rows_count = self.data.get_case_lines()for i in range(1,rows_count):is_run = self.data.get_is_run(i)if is_run:url = self.data.get_request_url(i)method = self.data.get_request_method(i)request_data = self.data.get_data_for_json(i)expect = self.data.get_expcet_data_for_mysql(i)header = self.data.is_header(i)depend_case = self.data.is_depend(i)if depend_case != None:self.depend_data = DependdentData(depend_case)#获取的依赖响应数据depend_response_data = self.depend_data.get_data_for_key(i)#获取依赖的keydepend_key = self.data.get_depend_field(i)request_data[depend_key] = depend_response_dataif header == 'write':res = self.run_method.run_main(method,url,request_data)op_header = OperationHeader(res)op_header.write_cookie()elif header == 'yes':op_json = OperetionJson('../dataconfig/cookie.json')cookie = op_json.get_data('apsid')cookies = {'apsid':cookie}res = self.run_method.run_main(method,url,request_data,cookies)else:res = self.run_method.run_main(method,url,request_data)if self.com_util.is_equal_dict(expect,res) == 0:self.data.write_result(i,'pass')pass_count.append(i)else:self.data.write_result(i,res)fail_count.append(i)self.send_mai.send_main(pass_count,fail_count)#将执行判断封装#def get_cookie_run(self,header):if __name__ == '__main__':run = RunTest()run.go_on_run()
总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

文档获取方式:

加入我的软件测试交流群:632880530免费获取~(同行大佬一起学术交流,每晚都有大佬直播分享技术知识点)

这份文档,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

以上均可以分享,只需要你搜索vx公众号:程序员雨果,即可免费领取

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

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

相关文章

ArcGIS10.8 连接 PostgreSQL 及遇到的两个问题

前提 以前同事用过我的电脑连PostgreSQL&#xff0c;失败了。当时不知道原因&#xff0c;只能使用GeoServer来发布数据了。现在终于搞明白了&#xff0c;原因是ArcGIS10.2版本太老&#xff0c;无法连接PostgreSQL9.4。参考这里 为了适应时代的发展&#xff0c;那我就用新的Ar…

与创新者同行,Apache Doris in 2023

在刚刚过去的 Doris Summit Asia 2023 峰会上&#xff0c;Apache Doris PMC 成员、飞轮科技技术副总裁衣国垒带来了“与创新者同行”的主题演讲&#xff0c;回顾了 Apache Doris 在过去一年所取得的技术突破与社区发展&#xff0c;重新思考了在面对海量数据实时分析上的挑战与机…

代码随想录算法训练营第四十七天丨 动态规划part10

121. 买卖股票的最佳时机 思路 动态规划 动规五部曲分析如下&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][0] 表示第i天持有股票所得最多现金 &#xff0c;这里可能有疑惑&#xff0c;本题中只能买卖一次&#xff0c;持有股票之后哪还有…

js将图片文件转为base64格式

/***图片文件转换成BASE64字符串&#xff0c;异步任务*param {File} file图片文件对象*return {String} BASE64字符串*/ const getBase64 (file: File) > new Promise((resolve: (url: string) > void, reject) > {const reader new FileReader();reader.onload ()…

Install Docker in Linux

Docker官网链接: https://docs.docker.com/ 1.确定Linux版本 新版本的Docker对Linux系统版本有一定的要求。如果Linux的发行版系统是centOS&#xff0c;安装最新版的docker需要centOS 7以上的系统。 在Docker安装帮助页面查看支持的系统版本。 Docker帮助页面:https://docs…

java excel、word、PPT转换成pdf预览

先引入包&#xff1a;[lib下载地址](https://mp.csdn.net/mp_download/manage/download/UpDetailed)Controllerpublic AjaxResult fileToPdf(RequestBody VerifyCode url, HttpServletResponse response, HttpServletRequest request) throws IOException {String fileUrl req…

迷雾系统-人物驱散迷雾

使用linerRender,将人物移动数据动态添加进去&#xff0c;同样是特殊层级让FogCamera渲染 EndCapVertices的数量越多&#xff0c;矩形就变为一个椭圆形的形状&#xff0c;更适合圆形视野探索 当拐点的两个点距离太近&#xff0c;LineRender会发生扭曲&#xff0c;解决方案是在…

【C++】类型转换 | IO流 | 空间配置器

C语言类型转换 C语言总共有两种形式的类型转换&#xff1a;隐式类型转换 和 显示类型转换。 C语言的转换格式虽然很简单&#xff0c;但也存在不少缺陷&#xff1a; 隐式类型转换有些情况下可能会引发意料之外的结果&#xff0c;比如数据精度丢失。显示类型转换的可视性比较差…

移植LVGL到单片机的一个demo简单介绍

简介 背景&#xff1a; 本文使用的是主控IC为stm32f103zet6, 显示IC为ST7735s&#xff0c;它是128*160的像素&#xff0c;色深为RGB565颜色。 官方虽然说LVGL移植平台只需 64kB 闪存和 8kB RAM 就足以满足简单的用户界面。但我移植到stm32f103c8t6&#xff0c;不管怎么修改配…

我干了8年测试,告诉你现在软件测试还能不能找到工作!

观点&#xff1a;如果你还是以前的思维来学习测试&#xff0c;那你肯定是找不到工作&#xff01; 我做测试工作有将近8年的时间&#xff0c;蚂蚁金服做过2年&#xff0c;因为加班太多离职了。目前在一家国企上市公司&#xff0c;一年能拿三四十个左右&#xff0c;对比头部互联…

可视化 | echarts饼图改编

echarts模板来源 &#x1f4da;改编点 &#x1f407;基本样式 去掉legend、label&#xff1a;show: false背景透明&#xff1a;backgroundColor: "transparent"去除功能标签添加载入动态animationEasing: elasticOut, animationDelay: function (idx) {return Mat…

【数据结构】顺序表 | 详细讲解

在计算机中主要有两种基本的存储结构用于存放线性表&#xff1a;顺序存储结构和链式存储结构。本篇文章介绍采用顺序存储的结构实现线性表的存储。 顺序存储定义 线性表的顺序存储结构&#xff0c;指的是一段地址连续的存储单元依次存储链性表的数据元素。 线性表的&#xf…

10-Docker-分布式存储算法

01-哈希取余算法分区 哈希取余分区&#xff08;Hash Modulus Partitioning&#xff09;是一种在分布式计算和数据存储中常用的分区策略&#xff0c;其目的是将数据或计算任务分配到多个节点或服务器上&#xff0c;以实现负载均衡和提高性能。这种分区策略的核心思想是使用哈希…

通过商品ID获取到京东商品详情页面数据,京东商品详情官方开放平台API接口,京东APP详情接口,可以拿到sku价格,销售价演示案例

淘宝SKU详情接口是指&#xff0c;获取指定商品的SKU的详细信息。SKU是指提供不同的商品参数组合的一个机制&#xff0c;通过不同的SKU来标识商品的不同组合形式&#xff0c;如颜色、尺寸等。SKU详情接口可以帮助开发者获取指定商品的SKU列表&#xff0c;以及每个SKU的属性、库存…

VirtualBox网络地址转换(NAT),宿主机无法访问虚拟机的问题

问题&#xff1a;NAT模式下&#xff0c;默认只能从内访问外面&#xff0c;而不能从外部访问里面&#xff0c;所以只能单向ping通&#xff0c;虚拟机的ip只是内部ip。 PS&#xff1a;桥接则是与主机公用网卡&#xff0c;有独立的外部ip。 解决&#xff1a;NAT模式可以通过配置 …

第十八章 Swing 程序设计

目录 概述 Swing常用窗体 JFrame 窗体 JDialog 对话框 JOptionPane 小型对话框 1.自定义对话框 2.确认框 3.输入框 4.通知框 常用布局管理器 null绝对布局 FlowLayout 流布局管理器 BorderLayout 边界布局管理器 GridLayout 网络布局管理器 常用面板 JPa…

Servlet作业小练习

一.题目 利用JavaBean实现用户类&#xff0c;包含姓名、性别、爱好&#xff0c;爱好需要用多选框 实现表单1进行获取数据&#xff0c;表单2显示获取结果。 利用Servlet实现逻辑代码 二.实现效果 三.具体实现 1.User实体类 package com.hjj.pojo.hw9;/*** author:嘉佳 Dat…

Halcon的相机内参外参的标定

halcon标定相机内参只能使用方向标定板和圆点标定板。并且方向标定板可也可用性极高。 1.打开halcon的标定助手&#xff0c;选择标定板的描述文件&#xff0c;填写标定板的厚度&#xff0c;根据相机选择像元的尺寸和镜头的焦距。如果已有相机内参&#xff0c;只标定外参&#…

设计模式(3)-结构型模式

结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低&#xff0c;满足“合成复用原则…

计算机网络第4章-通用转发和SDN

引子&#xff1a; 在前面&#xff0c;我们将基于目的地转发的特征总结为两个步骤&#xff1a; 查找目的IP地址&#xff08;匹配&#xff09;&#xff0c;然后将分组发送到有特定输出端口的交换结构&#xff08;“动作”&#xff09;。 但是这种转发特征会带来许多问题&#…