excel+requests管理测试用例接口自动化框架

背景:

某项目有多个接口,之前使用的unittest框架来管理测试用例,将每个接口的用例封装成一个py文件,接口有数据或者字段变动后,需要去每个py文件中找出变动的接口测试用例,维护起来不方便,为了便于接口变动后维护,使用excel来管理测试用例,接口有变动不需要修改代码,只需要维护excel即可。

思路:

为了方便维护测试用例,一个接口的测试用例使用一个excel文件来管理,每个excel文件中有两个sheet页,第一个sheet页是接口的基本信息,包括接口名称,地址和请求方式,第二个sheet页为接口的测试用例,如下图所示

第一个sheet页

第二个sheet页

 接口请求的数据类型为X-WWW-FORM-URLENCODED,在测试用例中每个字段为一列,每条用例为一行,倒数第二列为预期结果,倒数第三列为该条用例的描述。

接口自动化框架结构:

common目录存放公共的方法,例如写日志,连数据库

config目录存放配置文件和读取配置文件内容的方法,cfg.ini包括发送邮件的配置信息和接口的ip和端口

data目录存放接口的测试用例

logs目录存放用例执行的日志

report目录存放测试报告

run_main.py为用例执行的入口

源码:api_test.py封装读取测试用例的数据,执行测试用例和校验测试结果


#coding:utf-8import xlrd,os
import requests
from datetime import datetime
from xlrd import xldate_as_tuple
from config import readConfig
from common.logger import Log'''
获取测试用例data所在的目录
'''
d = os.path.dirname(__file__) #返回当前文件所在目录(common文件夹路径)
parent_path = os.path.dirname(d) #返回common的父级目录
data_path = os.path.join(parent_path,'data') #返回data所在目录
data_path1 = os.listdir(data_path) #返回data目录下所有的文件log = Log()def api_data():for filename in data_path1:book = xlrd.open_workbook(os.path.join(data_path,filename))'''获取excel文件中接口信息'''table = book.sheet_by_index(0) #通过索引,获取相应的列表,这里表示获取excel的第一个列表inf_name = table.row_values(1)[0] #返回接口名称inf_address = table.row_values(1)[1] #返回接口地址inf_mode = table.row_values(1)[2] #返回请求方式'''获取excel文件中测试用例信息'''sheet = book.sheet_by_index(1) #通过索引,获取相应的列表,这里表示获取excel的第二个列表nrows = sheet.nrows #获取所有行数filed = sheet.row_values(0)# print(filed)for i in range(1,nrows):d1 = {}for j in range(0,len(filed)-2):ctype = sheet.cell(i, j).ctype  # 表格的数据类型cell = sheet.cell_value(i, j)d = {}if ctype == 2 and cell % 1 == 0:  # 如果是整形cell = int(cell)elif ctype == 3:# 转成datetime对象date = datetime(*xldate_as_tuple(cell, 0))cell = date.strftime('%Y/%m/%d')elif ctype == 4:cell = True if cell == 1 else False# print(cell)d.update({filed[j]:cell})# print(d)d1.update(d)# print(d1)'''获取excel文件中测试用例预期结果和描述'''a = []for k in range(len(filed)-2,len(filed)):ctype = sheet.cell(i, k).ctype  # 表格的数据类型cell = sheet.cell_value(i, k)if ctype == 2 and cell % 1 == 0:  # 如果是整形cell = int(cell)elif ctype == 3:# 转成datetime对象date = datetime(*xldate_as_tuple(cell, 0))cell = date.strftime('%Y/%m/%d')elif ctype == 4:cell = True if cell == 1 else Falsea.append(cell)# print(a[0])# print(type(a[0]))'''获取cfg.ini配置文件中接口公共信息(ip和port)'''ip = readConfig.ip  # 获取配置文件中接口ipi_port = readConfig.i_port  # 获取配置文件中接口porturl = "http://" + ip + ":" + i_port + inf_addressheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0","X-Requested-With": "XMLHttpRequest","Connection": "keep-alive"}par = d1'''判断请求方式是GET还是POST,并且判断测试用例预期结果与实际响应一致'''if inf_mode == 'GET':r = requests.get(url, params=par)result = r.json()# log.info("---编号%s,接口名称%s---")%(i,inf_name)print(inf_name, str(result).replace('None','null'), a[1])if str(result).replace('None','null') == a[0]:log.info("pass")log.info("--------")else:log.info("false")log.info("--------")elif inf_mode == 'POST':r = requests.post(url, data=par, headers=headers)result = r.json()print(inf_name, str(result).replace('None', 'null'), a[1])if str(result).replace('None', 'null') == a[0]:print('pass')print('--------')else:print('false')print('--------')api_data()

配置文件cfg.ini(主要配置邮箱和接口ip+port等常用数据信息)


[email]smtp_server = smtp.163.com
port = 465
sender = xxx;psw是QQ邮箱的授权码
psw = xxx;收件人多个时,中间用逗号隔开,如'a@xx.com,b@xx.com'
receiver = xxx[interface]ip = xxx
;接口ip
port = xxx
;接口端口

readConfig.py读取配置文件中数据


# coding:utf-8
import os
import configparsercur_path = os.path.dirname(os.path.realpath(__file__))
configPath = os.path.join(cur_path, "cfg.ini")
conf = configparser.ConfigParser()
conf.read(configPath,encoding='utf-8')smtp_server = conf.get("email", "smtp_server")sender = conf.get("email", "sender")psw = conf.get("email", "psw")receiver = conf.get("email", "receiver")port = conf.get("email", "port")ip = conf.get("interface","ip")i_port = conf.get("interface","port")

优化:

部分接口访问时,响应未知用户,需要用session关联接口,先调用登录接口,把登录接口的调用封装成了一个实例方法,实现了复用,登录之后,登录接口的http响应会把session以 cookie的形式set到客户端,之后的接口都会使用此session去请求封装登录接口user_login.py


#coding:utf-8
import requests
from common.logger import Logclass Login():log = Log()def __init__(self,s):self.s = sdef login(self,code,passwd):url = "http://192.168.20.100:8081/backend/system/user/login"headers = {"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36","X-Requested-With":"XMLHttpRequest","Cookie":"JSESSIONID=92D7FB4C7FB917B7D2E8DC429A63443F","Connection":"keep-alive"}d = {"code":code,"passwd":passwd}res = self.s.post(url,headers=headers,data=d)result1 = res.text #字节输出self.log.info(u"调用登录方法,获取结果:%s"%result1)return res.json()

优化api_test.py中部分代码(红色部分为优化的代码)

1.在请求接口前首先调用登录接口2.加入执行用例的编号(p),每循环一次自增1


#coding:utf-8import xlrd,os
import requests
from datetime import datetime
from xlrd import xldate_as_tuple
from config import readConfig
from common.logger import Log
from case.user_login import Login'''
获取测试用例data所在的目录
'''
d = os.path.dirname(__file__) #返回当前文件所在目录(common文件夹路径)
parent_path = os.path.dirname(d) #返回common的父级目录
data_path = os.path.join(parent_path,'data') #返回data所在目录
data_path1 = os.listdir(data_path) #返回data目录下所有的文件s = requests.session()
lon = Login(s)
log = Log()def api_data():p = 1for filename in data_path1:book = xlrd.open_workbook(os.path.join(data_path,filename))'''获取excel文件中接口信息'''table = book.sheet_by_index(0) #通过索引,获取相应的列表,这里表示获取excel的第一个列表inf_name = table.row_values(1)[0] #返回接口名称inf_address = table.row_values(1)[1] #返回接口地址inf_mode = table.row_values(1)[2] #返回请求方式'''获取excel文件中测试用例信息'''sheet = book.sheet_by_index(1) #通过索引,获取相应的列表,这里表示获取excel的第二个列表nrows = sheet.nrows #获取所有行数filed = sheet.row_values(0)# print(filed)for i in range(1,nrows):d1 = {}for j in range(0,len(filed)-2):ctype = sheet.cell(i, j).ctype  # 表格的数据类型cell = sheet.cell_value(i, j)d = {}if ctype == 2 and cell % 1 == 0:  # 如果是整形cell = int(cell)elif ctype == 3:# 转成datetime对象date = datetime(*xldate_as_tuple(cell, 0))cell = date.strftime('%Y/%m/%d')elif ctype == 4:cell = True if cell == 1 else False# print(cell)d.update({filed[j]:cell})# print(d)d1.update(d)# print(d1)'''获取excel文件中测试用例预期结果和描述'''a = []for k in range(len(filed)-2,len(filed)):ctype = sheet.cell(i, k).ctype  # 表格的数据类型cell = sheet.cell_value(i, k)if ctype == 2 and cell % 1 == 0:  # 如果是整形cell = int(cell)elif ctype == 3:# 转成datetime对象date = datetime(*xldate_as_tuple(cell, 0))cell = date.strftime('%Y/%m/%d')elif ctype == 4:cell = True if cell == 1 else Falsea.append(cell)# print(a[0])# print(type(a[0]))'''获取cfg.ini配置文件中接口公共信息(ip和port)'''ip = readConfig.ip  # 获取配置文件中接口ipi_port = readConfig.i_port  # 获取配置文件中接口porturl = "http://" + ip + ":" + i_port + inf_addressheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0","X-Requested-With": "XMLHttpRequest","Connection": "keep-alive"}par = d1'''判断请求方式是GET还是POST,并且判断测试用例预期结果与实际响应一致,所有接口请求前先调用登录接口'''code = "xxx"  #登录接口用户codepasswd = "xxx" #登录接口用户passwdlon.login(code, passwd)if inf_mode == 'GET':r = s.get(url, params=par)result = r.json()log.info("编号:%s,接口名称:%s,测试点:%s,响应:%s"%(p,inf_name,a[1],str(result).replace('None','null')))# print(inf_name, str(result).replace('None','null'), a[1])if str(result).replace('None','null') == a[0]:log.info("pass")log.info("--------")else:log.info("false")log.info("--------")elif inf_mode == 'POST':r = s.post(url, data=par, headers=headers)result = r.json()log.info("编号:%s,接口名称:%s,测试点:%s,响应:%s" % (p, inf_name,a[1],str(result).replace('None', 'null')))# print(inf_name, str(result).replace('None', 'null'), a[1])if str(result).replace('None', 'null') == a[0]:log.info("pass")log.info("--------")else:log.info("false")log.info("--------")p=p+1api_data()

执行结果:

优化二:

excel中添加结果列,将每条用例的执行结果写入excel中,因为excel版本是2007以上,采用openpyxl模块去修改excel单元格的值,执行通过用绿色字体标注pass,执行不通过的用例红色字体标注false优化api_test.py中部分代码


#coding:utf-8import xlrd,os
import requests
import openpyxl
from openpyxl.styles import Font
# from xlutils.copy import copy
from datetime import datetime
from xlrd import xldate_as_tuple
from config import readConfig
from common.logger import Log
from case.user_login import Login'''
获取测试用例data所在的目录
'''
d = os.path.dirname(__file__) #返回当前文件所在目录(common文件夹路径)
parent_path = os.path.dirname(d) #返回common的父级目录
data_path = os.path.join(parent_path,'data') #返回data所在目录
data_path1 = os.listdir(data_path) #返回data目录下所有的文件s = requests.session()
lon = Login(s)
log = Log()def api_data():p = 1for filename in data_path1:book = xlrd.open_workbook(os.path.join(data_path,filename))'''使用xlwt操作excel,xlwt只支持excel2007以下版本'''# wb = copy(book)# ws = wb.get_sheet(1)'''使用openpyxl操作excel,openpyxl支持excel2007以上版本'''wb = openpyxl.load_workbook(os.path.join(data_path,filename))ws = wb.worksheets[1]font_green = Font(color="37b400")font_red = Font(color="ff0000")'''获取excel文件中接口信息'''table = book.sheet_by_index(0) #通过索引,获取相应的列表,这里表示获取excel的第一个列表inf_name = table.row_values(1)[0] #返回接口名称inf_address = table.row_values(1)[1] #返回接口地址inf_mode = table.row_values(1)[2] #返回请求方式'''获取excel文件中测试用例信息'''sheet = book.sheet_by_index(1) #通过索引,获取相应的列表,这里表示获取excel的第二个列表nrows = sheet.nrows #获取所有行数ncols = sheet.ncols #获取所有列数filed = sheet.row_values(0)# print(filed)for i in range(1,nrows):d1 = {}for j in range(0,len(filed)-3):ctype = sheet.cell(i, j).ctype  # 表格的数据类型cell = sheet.cell_value(i, j)d = {}if ctype == 2 and cell % 1 == 0:  # 如果是整形cell = int(cell)elif ctype == 3:# 转成datetime对象date = datetime(*xldate_as_tuple(cell, 0))cell = date.strftime('%Y/%m/%d')elif ctype == 4:cell = True if cell == 1 else False# print(cell)d.update({filed[j]:cell})# print(d)d1.update(d)# print(d1)'''获取excel文件中测试用例预期结果和描述'''a = []for k in range(len(filed)-3,len(filed)-1):ctype = sheet.cell(i, k).ctype  # 表格的数据类型cell = sheet.cell_value(i, k)if ctype == 2 and cell % 1 == 0:  # 如果是整形cell = int(cell)elif ctype == 3:# 转成datetime对象date = datetime(*xldate_as_tuple(cell, 0))cell = date.strftime('%Y/%m/%d')elif ctype == 4:cell = True if cell == 1 else Falsea.append(cell)# print(a[0])# print(type(a[0]))'''获取cfg.ini配置文件中接口公共信息(ip和port)'''ip = readConfig.ip  # 获取配置文件中接口ipi_port = readConfig.i_port  # 获取配置文件中接口porturl = "http://" + ip + ":" + i_port + inf_addressheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0","X-Requested-With": "XMLHttpRequest","Connection": "keep-alive"}par = d1'''判断请求方式是GET还是POST,并且判断测试用例预期结果与实际响应一致,所有接口请求前先调用登录接口'''code = "xuxingan"passwd = "admin"lon.login(code, passwd)if inf_mode == 'GET':r = s.get(url, params=par)result = r.json()log.info("编号:%s,接口名称:%s,测试点:%s,响应:%s"%(p,inf_name,a[1],str(result).replace('None','null')))# print(inf_name, str(result).replace('None','null'), a[1])if str(result).replace('None','null') == a[0]:# ws.write(i,ncols-1,'pass'.encode('utf-8'))ws.cell(row=i+1,column=ncols,value='pass').font = font_greenlog.info("pass")log.info("--------")else:# ws.write(i,ncols-1,'false'.encode('utf-8'))ws.cell(row=i+1, column=ncols, value='false').font = font_redlog.info("false")log.info("--------")elif inf_mode == 'POST':r = s.post(url, data=par, headers=headers)result = r.json()log.info("编号:%s,接口名称:%s,测试点:%s,响应:%s" % (p, inf_name,a[1],str(result).replace('None', 'null')))# print(inf_name, str(result).replace('None', 'null'), a[1])if str(result).replace('None', 'null') == a[0]:# ws.write(i,ncols-1,'pass'.encode('utf-8'))ws.cell(row=i+1, column=ncols, value='pass').font = font_greenlog.info("pass")log.info("--------")else:# ws.write(i,ncols-1,'false'.encode('utf-8'))ws.cell(row=i+1, column=ncols, value='false').font = font_redlog.info("false")log.info("--------")wb.save(os.path.join(data_path, filename))p=p+1log.info("总计%s条用例"%p)api_data()

执行结果

总结:

第一个版本有点粗糙,1.后续加入将每条用例的执行结果写入测试用例excel文件 2.生成自动化测试报告

Python接口自动化测试零基础入门到精通(2023最新版)

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

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

相关文章

双目视觉实战--单视图测量方法

目录 一.简介 二、2D变换 1. 等距变换(欧式变换) 2. 相似变换 3. 仿射变换 4. 射影变换(透视变换) 5. 结论 三、影消点与影消线 1. 平面上的线 2. 直线的交点 3. 2D无穷远点 4. 无穷远直线 5. 无穷远点的透视变换与仿…

Spring Cloud Gateway 使用 Redis 限流使用教程

从本文开始,笔者将总结 spring cloud 相关内容的教程 版本选择 为了适应 java8,笔者选择了下面的版本,后续会出 java17的以SpringBoot3.0.X为主的教程 SpringBoot 版本 2.6.5 SpringCloud 版本 2021.0.1 SpringCloudAlibaba 版本 2021.0.1.…

Prometheus的Pushgateway快速部署及使用

prometheus-pushgateway安装 一. Pushgateway简介 Pushgateway为Prometheus整体监控方案的功能组件之一,并做于一个独立的工具存在。它主要用于Prometheus无法直接拿到监控指标的场景,如监控源位于防火墙之后,Prometheus无法穿透防火墙&…

C++基础——内存分区模型

1 概述 C程序在执行是,将内存大致分为4个区域: 代码区:用于存放二进制代码,由操作系统进行管理全局区:存放全局变量和静态变量及常量栈区:由编译器自动分配释放,存放函数的参数、局部变量等堆…

回首往昔,初学编程那会写过的两段愚蠢代码

一、关于判断两个整数是否能整除的GW BASIC创意代码 记得上大学时第一个编程语言是BASIC,当时Visual Basic还没出世,QBASIC虽然已经在1991年随MS-DOS5.0推出了,但我们使用的还是 GW-BASIC, 使用的教材是谭浩强、田淑清编著的《BA…

【广州华锐互动】VR建筑安全培训体验为建筑行业人才培养提供有力支持

随着建筑行业的快速发展,建筑施工安全问题日益受到广泛关注。然而,传统的安全培训方式往往缺乏实践性和真实性,难以让员工真正掌握安全操作技能。近年来,虚拟现实(VR)技术的广泛应用为建筑施工安全培训提供了新的机遇。 虚拟现实技…

金融用户实践|分布式存储支持数据仓库业务系统性能验证

作者:深耕行业的 SmartX 金融团队 闫海涛 估值是指对资产或负债的价值进行评估的过程,这对于投资决策具有重要意义。每个金融公司资管业务人员都期望能够实现实时的业务估值,快速获取最新的数据和指标,从而做出更明智的投资决策。…

【数组的使用续篇】

文章目录 以数组的形式打印数组打印方法:Arrays.toString(数组名) 数组排序大小排序方法是 Arrays.sort(数组名) 创建一个自己的打印数组的方法自己创建一个冒泡排序两数之间交换方法 逆置数组打印核心思路还是 i 和 j 交换 总结 以数组的形式打印数组 打印方法&am…

软件测试用例设计方法-因果图法

边界值法是等价类划分法的补充,所以,它们是一对搭档。 那么,判定表法有没有它的搭档呢? 答案是,有的。那就是本篇文章分享的用例设计方法—— 因果图法 。 定义 因果图法: 用来处理等价类划分和边界值…

三维地图开发三维地图服务器

三维地图开发三维地图服务器 发布时间:2020-03-03 版权: 搭建离线地图服务主要是两个步骤:一是:下载离线地图服务需要的地图数据;二是:将下载的离线地图数据发布成地图服务;只有做好这两步&…

出差学小白知识No5:ubuntu连接开发板|上传源码包|板端运行的环境部署

1、ubuntu连接开发板&#xff1a; 在ubuntu终端通过ssh协议来连接开发板&#xff0c;例如&#xff1a; ssh root<IP_address> 即可 这篇文章中也有关于如何连接开发板的介绍&#xff0c;可以参考SOC侧跨域实现DDS通信总结 2、源码包上传 通过scp指令&#xff0c;在ub…

python使用dataset快速使用SQLite

目录 一、官网地址 二、安装 三、 快速使用 一、官网地址 GitHub - pudo/dataset: Easy-to-use data handling for SQL data stores with support for implicit table creation, bulk loading, and transactions. 二、安装 pip install dataset 如果是mysql&#xff0c;则…

堆/二叉堆详解[C/C++]

前言 堆是计算机科学中-类特殊的数据结构的统称。实现有很多,例如:大顶堆,小顶堆&#xff0c;斐波那契堆&#xff0c;左偏堆&#xff0c;斜堆等等。从子结点个数上可以分为二汊堆&#xff0c;N叉堆等等。本文将介绍的是二叉堆。 二叉堆的概念 1、引例 我们小时候&#xff0c;基…

left join时筛选条件对查询结果的

-- 创建表 CREATE TABLE table1 (id int(11) NOT NULL AUTO_INCREMENT,card_num varchar(60) DEFAULT NULL,customer_id varchar(60) DEFAULT NULL,PRIMARY KEY (id) ) ENGINE InnoDBAUTO_INCREMENT 12DEFAULT CHARSET utf8mb4 COMMENT 测试表1;-- 创建表 CREAT…

44springboot摄影跟拍预定管理系统

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

basic_sr介绍

文章目录 pytorch基础知识和basicSR中用到的语法1.Sampler类与4种采样方式2.python dict的get方法使用3.prefetch_dataloader.py4. pytorch 并行和分布式训练4.1 选择要使用的cuda4.2 DataParallel使用方法常规使用方法保存和载入 4.3 DistributedDataParallel 5.wangdb 入门5.…

众佰诚:抖音小店的体验分什么时候更新

随着移动互联网的发展&#xff0c;越来越多的电商平台开始涌现&#xff0c;其中抖音小店作为一种新型的电商模式&#xff0c;受到了许多用户的欢迎。然而&#xff0c;对于抖音小店的体验分更新时间&#xff0c;很多用户并不是很清楚。本文将对此进行详细的解答。 首先&#xff…

SimpleCG图像操作基础

上一篇我们介绍了程序的交互功能&#xff0c;就可以编写一些简单的游戏了&#xff0c;例如贪吃蛇、扫雷、俄罗斯方块、五子棋等&#xff0c;都可以使用图形函数直接绘制&#xff0c;在后续文章中将逐一展示。不过编写画面丰富游戏离不开图像&#xff0c;所以本篇我们介绍一下基…

智能合同和TikTok:揭示加密技术的前景

在当今数字化时代&#xff0c;智能合同和加密技术都成为了技术和商业世界中的热门话题。它们代表了一个崭新的未来&#xff0c;有着潜在的巨大影响。 然而&#xff0c;你或许从未想过将这两者联系在一起&#xff0c;直到今天。本文将探讨智能合同和TikTok之间的联系&#xff0…

联想G50笔记本直接使用F键功能(F1~F12)需要在BIOS设置关闭热键功能可以这样操作!

如果开启启用热键模式按F1就会出现FnF1的效果&#xff0c;不喜欢此方式按键的用户可以进入BIOS设置界面停用热键模式即可。 停用热键模式方法如下&#xff1a; 1、重新启动笔记本电脑&#xff0c;当笔记本电脑屏幕出现Lenovo标识的时候&#xff0c;立即按FnF2进入BIOS设置界面…