浙江省建设业协会网站/重庆seo网站排名
前言:上篇文章python3+requests+unittest:接口自动化测试(一):已经介绍了基于unittest框架的实现接口自动化,但是也存在一些问题,比如最明显的测试数据和业务没有区分开,接口用例不便于管理等,所以又对此修改完善。接下来主要是介绍该套接口自动化框架的设计到实现,参考代码的git地址:https://github.com/zhangying123456/python3_interface
1.代码框架展示
(1)case:存放测试用例数据的,比如请求类型get/post、请求url、请求header、请求数据等;
(2)data:获取excel文件中相应数据的方法封装,获取excel中对应表格内的数据,excel的行列数据等:get_data.py;判断用例之间是否存在依赖关系并获取依赖数据:dependent_data.py;初始化excel文件:data_config.py;
(3)dataconfig:存放请求中涉及到的header、data、cookies等数据;
(4)log:存放测试完成之后生成的日志文件,可以查看日志定位问题;
(5)main:脚本执行的主函数run_test.py
(6)util:通用方法的封装,各种不同断言方式common_assert.py;对excel文件的读写操作operation_excel.py;从请求返回数据中拿取数据作为下一个接口的请求header数据operation_header.py;从json文件中拿取想要的数据operation_json.py;将接口自动化过程中的相关日志输出到log.txt中print_log.py;根据请求类型的不同执行对应的get/post方法runmethod.py;将测试结果以邮件形式发送给相关人员send_mail.py。
2.代码实现说明
(1)首先看下用例数据
说明:该用例只是用来覆盖一些接口场景而测试使用的,有兴趣的可以参考源码用自己项目的真实数据来实现
先判断是否执行:如果yes,执行该条用例;如果no,直接跳过该条用例。
执行用例:获取用例的url、请求类型、请求头header、请求数据,request.get/post执行该条接口用例。
在执行用例过程中,会存在特殊情况:(1)比如test_04依赖于test_03,test_04中的请求字段supplier的参数数据来源于test_03的response中value[0].biz字段的数据,所以在执行接口过程中需要判断是否存在依赖关系;(2)比如test_06请求数据需要test_05的response中的cookies数据,所以这种类型接口也要特殊处理。
执行完成后:写入实际结果,与预期结果做对比,进行断言。
(2)看了用例excel后,对基本的流程有个大概了解,现在的问题就是如何拿取对应的数据执行接口得到运行结果
if is_run:url = self.data.get_request_url(i)method = self.data.get_request_method(i)#获取请求参数data = self.data.get_data_value(i)# 获取excel文件中header关键字header_key = self.data.get_request_header(i)# 获取json文件中header_key对应的头文件数据header = self.data.get_header_value(i)expect = self.data.get_expect_data(i)depend_case = self.data.is_depend(i)
举例说明1:请求url数据是存放在excel中,我们通过操作excel文件到特定单元格拿到url数据
#获取urldef get_request_url(self,row):col = int(data_config.get_url())url = self.oper_excel.get_cell_value(row,col)return url
举例说明2:请求头header或者请求数据中有的数据为空,所以我们在拿取数据过程中要做判断
#获取请求数据def get_request_data(self,row):col = int(data_config.get_data())data = self.oper_excel.get_cell_value(row,col)if data == '':return Nonereturn data
首先拿取excel中表格中的关键字,再通过关键字去对应json文件拿取具体的请求数据。比如先拿取excel中请求数据中的hotwords,再根据此关键字去json文件读取hotwords的键值数据
"hotwords": {"bizName": "globalSearchClient","sign": "8c8bc3ee9d6c4b7b8a390ae298cb6db5","timeMills": "1524906299999"}
#通过获取请求关键字拿到data数据def get_data_value(self,row):oper_json = OperationJson('../dataconfig/request_data.json')request_data = oper_json.get_data(self.get_request_data(row))return request_data
#根据关键字获取数据'''dict['key']只能获取存在的值,如果不存在则触发KeyErrordict.get(key, default=None),返回指定键的值,如果值不在字典中返回默认值Noneexcel文件中请求数据有可能为空,所以用get方法获取'''def get_data(self,key):# return self.data[key]return self.data.get(key)
(3)一般的接口都是单接口,即是单独请求,没有上下依赖关系的,针对这种只要模拟请求拿到数据进行断言就可以了。但是实际项目中会存在特殊场景,比如test_03和test04
说明:test_04中,请求数据qqmusic_more中的supplier字段依赖于test_03中的返回数据value[0].biz的值
"qqmusic_more": {"bizName": "globalSearchClient","appLan": "zh_CN","musicLimit": "20","imei": "864044030085594","keyword": "fly","timeMills": "1527134461256","page": "0","sign": "17daa7e3e84bd4dfbe9a1bd9a1bd7e62","mac": "90f05205d7b7","sessionId": "43e605b914874cd99b47ac997e19c1a1","network": "1","supplier": "","language": "zh_CN",}
先执行test_03,获取依赖的返回数据value[0].biz的值
#执行依赖测试,获取test_03返回结果def run_dependent(self):row_num = self.oper_excel.get_row_num(self.case_id)request_data = self.data.get_data_value(row_num)header = self.data.get_request_header(row_num)method = self.data.get_request_method(row_num)url = self.data.get_request_url(row_num)res = self.method.run_main(method,url,request_data,header,params=request_data)return res#获取依赖字段的响应数据:通过执行依赖测试case来获取响应数据,响应中某个字段数据作为依赖key的valuedef get_value_for_key(self,row):#获取依赖的返回数据keydepend_data = self.data.get_depend_key(row)print(depend_data) #depend_data打印数据:value[0].biz#执行依赖case返回结果response_data = self.run_dependent()# print(depend_data)# print(response_data)return [match.value for match in parse(depend_data).find(response_data)][0]
再将value[0].biz值放入test_04请求数据qqmusic_more中的supplier字段中
if depend_case != None:self.depend_data = DependentData(depend_case)#获取依赖字段的响应数据depend_response_data = self.depend_data.get_value_for_key(i)#获取请求依赖的keydepend_key = self.data.get_depend_field(i)#将依赖case的响应返回中某个字段的value赋值给该接口请求中某个参数data[depend_key] = depend_response_data
(4)拿到请求相关数据后,执行该条case,获取response;然后实际结果与预期结果进行断言
res = self.run_method.run_main(method,url,data,header,params=data)
'''
get请求参数是params:request.get(url='',params={}),post请求数据是data:request.post(url='',data={})
excel文件中没有区分直接用请求数据表示,则data = self.data.get_data_value(i)拿到的数据,post请求就是data=data,get请就是params=data
'''
根据get、post类型区分
class 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,params=None,header=None):res = Noneif header != None:res = requests.get(url=url, params=params, headers=header)else:res = requests.get(url=url, params=params)return res.json()def run_main(self,method,url,data=None,header=None,params=None):res = Noneif method == 'post':res = self.post_main(url,data,header)else:res = self.get_main(url,params,header)return res
(5)执行接口case过程中,可能存在某条case异常报错,导致下面的case无法运行,所以我们既要将异常日志存放在特定文件中方便后续排查,也要保证下面的case能够不受影响继续执行完
try:...except Exception as e:# 将报错写入指定路径的日志文件里with open(log_file,'a',encoding='utf-8') as f:f.write("\n第%s条用例报错:\n" % i)initLogging(log_file,e)fail_count.append(i)
抓取日志的方法可以使用python内置模块logging,具体用法可以参考:https://www.cnblogs.com/shapeL/p/9174303.html
import loggingdef initLogging(logFilename,e):logging.basicConfig(level = logging.INFO,format ='%(asctime)s-%(levelname)s-%(message)s',datefmt = '%y-%m-%d %H:%M',filename = logFilename,filemode = 'a')fh = logging.FileHandler(logFilename,encoding='utf-8')logging.getLogger().addHandler(fh)log = logging.exception(e)return log
日志文件log.txt结果:直接定位问题出在哪儿
第5条用例报错:
18-06-19 10:27-ERROR-string indices must be integers
Traceback (most recent call last):File "C:/Users/xxx/Documents/GitHub/python3_interface/main/run_test.py", line 70, in go_on_runop_header.write_cookie()File "C:\Users\xxx\Documents\GitHub\python3_interface\util\operation_header.py", line 30, in write_cookiecookie = requests.utils.dict_from_cookiejar(self.get_cookie())File "C:\Users\zhangying1\Documents\GitHub\python3_interface\util\operation_header.py", line 25, in get_cookieurl = self.get_response_url()+"&callback=jQuery21008240514814031887_1508666806688&_=1508666806689"File "C:\Users\xxx\Documents\GitHub\python3_interface\util\operation_header.py", line 18, in get_response_urlurl = self.response['data']['url'][0]
TypeError: string indices must be integers
(6)接口自动化测试执行完成后,需要将测试结果发送给项目组相关人员,邮件发送实现方法参考:https://www.cnblogs.com/shapeL/p/9115887.html
self.send_mail.send_main(pass_count,fail_count,no_run_count)
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import datetimeclass SendEmail:global send_userglobal email_hostglobal passwordpassword = "lunkbrgwqxhfjgxx"email_host = "smtp.qq.com"send_user = "xxx@qq.com"def send_mail(self,user_list,sub,content):user = "shape" + "<" + send_user + ">"# 创建一个带附件的实例message = MIMEMultipart()message['Subject'] = submessage['From'] = usermessage['To'] = ";".join(user_list)# 邮件正文内容message.attach(MIMEText(content, 'plain', 'utf-8'))# 构造附件(附件为txt格式的文本)filename = '../log/log.txt'time = datetime.date.today()att = MIMEText(open(filename, 'rb').read(), 'base64', 'utf-8')att["Content-Type"] = 'application/octet-stream'att["Content-Disposition"] = 'attachment; filename="%s_Log.txt"'% timemessage.attach(att)server = smtplib.SMTP_SSL()server.connect(email_host,465)# 启用SSL发信, 端口一般是465# server.set_debuglevel(1)# 打印出和SMTP服务器交互的所有信息server.login(send_user,password)server.sendmail(user,user_list,message.as_string())server.close()def send_main(self,pass_list,fail_list,no_run_list):pass_num = len(pass_list)fail_num = len(fail_list)#未执行的用例no_run_num = len(no_run_list)count_num = pass_num + fail_num + no_run_num#成功率、失败率'''用%对字符串进行格式化%d 格式化整数%f 格式化小数;想保留两位小数,需要在f前面加上条件:%.2f;用%%来表示一个%如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串 '''pass_result = "%.2f%%" % (pass_num/count_num*100)fail_result = "%.2f%%" % (fail_num/count_num*100)no_run_result = "%.2f%%" % (no_run_num/count_num*100)user_list = ['xxx@qq.com']sub = "接口自动化测试报告"content = "接口自动化测试结果:\n通过个数%s个,失败个数%s个,未执行个数%s个:通过率为%s,失败率为%s,未执行率为%s\n日志见附件" % (pass_num,fail_num,no_run_num,pass_result,fail_result,no_run_result)self.send_mail(user_list,sub,content)
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
软件测试面试小程序
被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!
涵盖以下这些面试题板块:
1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux
6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!
相关文章:

python3+requests:接口自动化测试(二)
前言:上篇文章python3requestsunittest:接口自动化测试(一):已经介绍了基于unittest框架的实现接口自动化,但是也存在一些问题,比如最明显的测试数据和业务没有区分开,接口用例不便于…...

uni-app:允许字符间能自动换行(英文字符、数字等)
<template><view class"container"><!-- 这里是你的文本内容 -->{{ multilineText }}</view> </template><style> .container {word-break: break-all; } </style>例如: <template><view class"…...

day 42 |● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II
121. 买卖股票的最佳时机 dp数组需要记录两种状态,一种是当天时手中还持有股票,一种是当天时手中已卖出股票。 func maxProfit(prices []int) int {dp : make([][]int, len(prices))dp[0] []int{-prices[0], 0}for i : 1; i < len(prices); i{val0…...

SQLserver基础入门理论(超基础)
♥️作者:小刘在C站 ♥️个人主页: 小刘主页 ♥️努力不一定有回报,但一定会有收获加油!一起努力,共赴美好人生! ♥️学习两年总结出的运维经验,以及思科模拟器全套网络实验教程。专栏…...

(三)行为模式:7、观察者模式(Observer Pattern)(C++示例)
目录 1、观察者模式(Observer Pattern)含义 2、观察者模式的UML图学习 3、观察者模式的应用场景 4、观察者模式的优缺点 (1)优点: (2)缺点 5、C实现观察者模式的实例 1、观察者模式&…...

2019CVPR Semantic Graph Convolutional Networks for 3D Human Pose Regression
基于语义图卷积网络的三维人体姿态回归 源码 https://github.com/garyzhao/SemGCN 摘要 在本文中,我们研究了学习图卷积网络(GCN)回归的问题。GCN的当前体系结构受限于卷积滤波器和共享的变换矩阵为的小感受野。为了解决这些限制ÿ…...

大数据课程K16——Spark的梯度下降法
文章作者邮箱:yugongshiyesina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Spark的梯度下降法; ⚪ 了解Spark的梯度下降法家族(BGD,SGD,MBGD); ⚪ 掌握Spark的MLlib实现…...

springboot:时间格式化的5种方法(解决后端传给前端的时间格式转换问题)推荐使用第4和第5种!
本文转载自:springboot:时间格式化的5种方法(解决后端传给前端的时间显示不一致)_为什么前端格式化日期了后端还要格式化_洛泞的博客-CSDN博客 时间问题演示 为了方便演示,我写了一个简单 Spring Boot 项目ÿ…...

六、vim编辑器的使用
1、编辑器 (1)编辑器就是一款软件。 (2)作用就是用来编辑文件,譬如编辑文字、编写代码。 (3)Windows中常用的编辑器,有自带的有记事本(notepad),比较好用的notepad、VSCode等。 (4)Linux中常用的编辑器,自带的最古老的vi&…...

【易售小程序项目】项目介绍与系列文章集合
项目介绍 易售二手小程序主要用于校园中二手商品的交易,该系列文章会记录这个小程序前端的整个开发过程并提供详细代码,后台主要基于若依管理系统搭建,文章中也会提及后端关键部分的实现及代码。希望该系列文章可以帮助小白了解项目的开发流…...

游戏服务器成DDoS最大攻击重灾区
游戏产业的迅猛发展也让游戏产业成为被黑客攻击的重灾区。什么原因让游戏行业成为DDoS的攻击重点。总结有如下原因和主要手段: 1.游戏行业的攻击成本较低,攻防成本1:N。随着DDoS攻击的打法越来越复杂,攻击点更是越来越多ÿ…...

[SpringBoot3]博客管理系统(源码放评论区了)
八、博客管理系统 创建新的SpringBoot项目,综合运用以上知识点,做一个文章管理的后台应用。依赖: Spring WebLombokThymeleafMyBatis FrameworkMySQL DriverBean Validationhutool 需求:文章管理工作,发布新文章&…...

C语言——指针基本语法
概述 内存地址 在计算机内存中,每个存储单元都有一个唯一的地址(内存编号)。 通俗理解,内存就是房间,地址就是门牌号 指针和指针变量 指针(Pointer)是一种特殊的变量类型,它用于存储内存地址。 指针的实…...

elementui table 在浏览器分辨率变化的时候界面异常
异常点: 界面显示不完整,表格卡顿,界面已经刷新完成,但是表格的宽度还在一点一点变化,甚至有无线延伸的情况 思路: 1. 使用doLayout 这里官方文档有说明, 所以我的想法是,监听浏览…...

六、Kafka-Eagle监控
目录 6.1 MySQL 环境准备6.2 Kafka 环境准备6.3 Kafka-Eagle 安装 6.1 MySQL 环境准备 Kafka-Eagle 的安装依赖于 MySQL,MySQL 主要用来存储可视化展示的数据 6.2 Kafka 环境准备 修改/opt/module/kafka/bin/kafka-server-start.sh 命令 vim bin/kafka-server-sta…...

DBeaver 23.1.5 发布
导读DBeaver 是一个免费开源的通用数据库工具,适用于开发人员和数据库管理员。DBeaver 23.1.5 现已发布,更新内容如下. Data editor 重新设计了词典查看器面板 UI 空间数据类型:曲线几何线性化已修复 数据保存时结果选项卡关闭的问题已解决…...

三种垃圾收集算法,优缺点分析,设计垃圾收集
文章目录 垃圾收集算法标记-清除(基础收集算法)标记-复制(新生代)标记-整理(老年代) 垃圾收集算法 标记-清除(基础收集算法) 首先标记出所有需要回收的对象,在标记完成后…...

【链表OJ 10】环形链表Ⅱ(求入环节点)
前言: 💥🎈个人主页:Dream_Chaser~ 🎈💥 ✨✨刷题专栏:http://t.csdn.cn/UlvTc ⛳⛳本篇内容:力扣上链表OJ题目 目录 leetcode142. 环形链表 II 1.问题描述 2.代码思路 3.问题分析 leetcode142. 环形链…...

RT-Thread在STM32硬件I2C的踩坑记录
RT-Thread在STM32硬件I2C的踩坑记录 0.前言一、软硬件I2C区别二、RT Thread中的I2C驱动三、尝试适配硬件I2C四、i2c-bit-ops操作函数替换五、Attention Please!六、总结 参考文章: 1.将硬件I2C巧妙地将“嫁接”到RTT原生的模拟I2C驱动框架 2.基于STM32F4平台的硬件I…...

小白学Go基础01-Go 语言的介绍
Go 语言对传统的面向对象开发进行了重新思考,并且提供了更高效的复用代码的手段。Go 语言还让用户能更高效地利用昂贵服务器上的所有核心,而且它编译大型项目的速度也很快。 用 Go 解决现代编程难题 Go 语言开发团队花了很长时间来解决当今软件开发人员…...

Spring工具类--Assert的使用
原文网址:Spring工具类--Assert的使用_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Spring的Assert工具类的用法。 Assert工具类的作用:判断某个字段,比如:断定它不是null,如果是null,则此工具类会报…...

无涯教程-Android - Absolute Layout函数
Absolute Layout 可让您指定其子级的确切位置(x/y坐标),绝对布局的灵活性较差且难以维护。 Absolute Layout - 属性 以下是AbsoluteLayout特有的重要属性- Sr.NoAttribute & 描述1 android:id 这是唯一标识布局的ID。 2 android:layout_x 这指定视图的x坐标…...

2018ECCV Can 3D Pose be Learned from2D Projections Alone?
摘要 在计算机视觉中,从单个图像的三维姿态估计是一个具有挑战性的任务。我们提出了一种弱监督的方法来估计3D姿态点,仅给出2D姿态地标。我们的方法不需要2D和3D点之间的对应关系来建立明确的3D先验。我们利用一个对抗性的框架,强加在3D结构…...

干旱演变研究:定义及研究方法
在水文系统中,每个组分之间互相关联,包气带水、地下水和河川径流相互响应,水文循环处于动态平衡的状态。 降水作为水文系统的输入量,对水文循环具有重要的影响。降水短缺通过水文循环导致水文系统不同组分(包气带、地下水和地表水)发生干旱,降水不足导致土壤含水量减少,…...

【LeetCode-中等题】114. 二叉树展开为链表
文章目录 题目方法一:前序遍历(构造集合) 集合(构造新树)方法二:原地构建方法三:前序遍历--迭代(构造集合) 集合(构造新树) 题目 方法一&#x…...

【题解】JZOJ6645 / 洛谷P4090 [USACO17DEC] Greedy Gift Takers P
洛谷 P4090 [USACO17DEC] Greedy Gift Takers P 题意 n n n 头牛排成一列,队头的奶牛 i i i 拿一个礼物并插到从后往前数 c i c_i ci 头牛的前面,重复无限次,问多少奶牛没有礼物。 题解 发现若一头牛无法获得礼物,那么它后…...

Vue 项目中的错误如何处理的?
1、 组件中的处理:使用 errorCaptured 钩子 作用:可以捕获来自后代组件的错误 父组件(errorCaptured) -> 子组件 (errorCaptured) -> 当孙子组件出错时,错误会一直向上抛,也就是先触发子组件的 errorCaptured,…...

网络分层的真实含义
复杂的程序都要分层,这是程序设计的要求。比如,复杂的电商还会分数据库层、缓存层、Compose 层、Controller 层和接入层,每一层专注做本层的事情。 当一个网络包从一个网口经过的时候,你看到了,首先先看看要不要请进来…...

RT-Thread 线程间同步
线程间同步 在多线程实时系统中,一项工作的完成往往可以通过多个线程协调的方式共同来完成,那么多个线程之间如何 “默契” 协作才能使这项工作无差错执行?下面举个例子说明。 例如一项工作中的两个线程:一个线程从传感器中接收…...

Python元类再解释
Python元类再解释 元类是什么? 你可以把元类看作是“生产类的工厂”。就像类是用来生产对象的,元类是用来生产类的。 为什么需要元类? 考虑一个场景:假设你正在编写一个框架,你希望框架中的所有类都有某些特定的方…...