背景:

某项目有多个接口,之前使用的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-8

import 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 False
a.append(cell)
# print(a[0])
# print(type(a[0])) '''
获取cfg.ini配置文件中接口公共信息(ip和port)
'''
ip = readConfig.ip # 获取配置文件中接口ip
i_port = readConfig.i_port # 获取配置文件中接口port
url = "http://" + ip + ":" + i_port + inf_address
headers = {
"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 configparser cur_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 Log class Login():
log = Log() def __init__(self,s):
self.s = s def 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-8

import 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 = 1
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 False
a.append(cell)
# print(a[0])
# print(type(a[0])) '''
获取cfg.ini配置文件中接口公共信息(ip和port)
'''
ip = readConfig.ip # 获取配置文件中接口ip
i_port = readConfig.i_port # 获取配置文件中接口port
url = "http://" + ip + ":" + i_port + inf_address
headers = {
"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" #登录接口用户code
passwd = "xxx" #登录接口用户passwd
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]:
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+1 api_data()

执行结果:

优化二:

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

优化api_test.py中部分代码

#coding:utf-8

import 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 = 1 for 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 False
a.append(cell)
# print(a[0])
# print(type(a[0])) '''
获取cfg.ini配置文件中接口公共信息(ip和port)
'''
ip = readConfig.ip # 获取配置文件中接口ip
i_port = readConfig.i_port # 获取配置文件中接口port
url = "http://" + ip + ":" + i_port + inf_address
headers = {
"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_green
log.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_red
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]:
# ws.write(i,ncols-1,'pass'.encode('utf-8'))
ws.cell(row=i+1, column=ncols, value='pass').font = font_green
log.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_red
log.info("false")
log.info("--------")
wb.save(os.path.join(data_path, filename))
p=p+1 log.info("总计%s条用例"%p) api_data()

执行结果

总结:

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

excel+requests管理测试用例接口自动化框架的更多相关文章

  1. 转载:python + requests实现的接口自动化框架详细教程

    转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实现的接口自动化框架详细教程 前段时间由于公司测试方向的转型,由 ...

  2. python + requests实现的接口自动化框架详细教程

    前段时间由于公司测试方向的转型,由原来的web页面功能测试转变成接口测试,之前大多都是手工进行,利用postman和jmeter进行的接口测试,后来,组内有人讲原先web自动化的测试框架移驾成接口的自 ...

  3. Python+Unittest+Requests+PyMysql+HTMLReport 接口自动化框架

    整体框架使用的是:Python+Unittest+Requests+PyMysql+HTMLReport  多线程并发模式 主要依赖模块 Unittest.Requests.PyMysql.HTMLR ...

  4. python+requests接口自动化框架

    为什么要做接口自动化框架 1.业务与配置的分离 2.数据与程序的分离:数据的变更不影响程序 3.有日志功能,实现无人值守 4.自动发送测试报告 5.不懂编程的测试人员也可以进行测试 正常接口测试的流程 ...

  5. Python+Pytest+Allure+Git+Jenkins接口自动化框架

    Python+Pytest+Allure+Git+Jenkins接口自动化框架 一.接口基础 接口测试是对系统和组件之间的接口进行测试,主要是效验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系. ...

  6. python+request接口自动化框架

    python+request接口自动化框架搭建 1.数据准备2.用python获取Excel文件中测试用例数据3.通过requests测试接口4.根据接口返回的code值和Excel对比 但本章只讲整 ...

  7. 接口自动化框架(Pytest+request+Allure)

    前言: 接口自动化是指模拟程序接口层面的自动化,由于接口不易变更,维护成本更小,所以深受各大公司的喜爱. 接口自动化包含2个部分,功能性的接口自动化测试和并发接口自动化测试. 本次文章着重介绍第一种, ...

  8. python3+request接口自动化框架

    首次书写博客,记录下写的自动化接口框架,框架比较简单,哈哈哈,算是记录下历程把!~~~ 一.本次框架由python3.6 书写 1.准备代码环境,下载python3.6    下载地址:https:/ ...

  9. 接口自动化框架2-升级版(Pytest+request+Allure)

    前言: 接口自动化是指模拟程序接口层面的自动化,由于接口不易变更,维护成本更小,所以深受各大公司的喜爱. 第一版入口:接口自动化框架(Pytest+request+Allure) 本次版本做了一些升级 ...

随机推荐

  1. [HNOI2012] 永无乡 题解

    题意: n个点,有加边操作,询问与某一点处于相同的联通块的点中权值第k大的点 思路: 对所有点建立一棵权值线段树,加边就配合并查集进行线段树合并 反思: 动态开点,权值线段树要用sum[g[x=fin ...

  2. 【HDOJ6299】Balanced Sequence(贪心)

    题意:给定n个只有左右括号的序列,要求将它们重新排序使得匹配的括号对数最大. n<=1e5 s[i]<=1e5 sum s[i]<=5e6 思路: 先把每个串内部的匹配数量减去,剩下 ...

  3. UINavigationController 小记

    1.以栈的形式管理视图控制器,push 和 pop 方法来弹入和弹出控制器,最多只能显示一个视图控制器. 2.使用pop方法可以移除栈顶控制器,当一个控制器被pop后,控制器内存会被释放了. 3.一层 ...

  4. PHP移植

    1. 首先交叉编译zlib. CC=arm-linux-gcc ./configure --sahred --prefix=/usr/local/arm/3.4.1/arm-linux make&am ...

  5. 学习swift从青铜到王者之swift枚举07

    空枚举 //空枚举 enum SomeEnumeration { // enumeration definition goes here } 枚举基本类型 //枚举基本类型 enum CompassP ...

  6. 【网络】TCP的流量控制

    一.利用滑动窗口实现流量控制 流量控制是让发送方的发生速率不要太快,要让接收方来得及接收. 发送方的发送窗口不能超过接收方给出的接收窗口的数值,TCP的窗口单位是字节,不是报文段. TCP为每一个连接 ...

  7. Windows7系统下优化固态硬盘

    一.AHCI硬盘模式可提高硬盘性能,确定你的固态硬盘是运行在AHCI模式下,打开“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Servicesmsahci” ...

  8. 静态网页怎样实现动态交互?-JavaScript

    在Html基础上,javascript能够开发交互式web网页.javascript的出现使得网页和用户之间实现了一种实时性的.动态的.交互性的关系,javascript短小精悍,又是在客户机上执行的 ...

  9. ext.net 2.5 导出excel的使用方法

    前台页面的导入,导出 <ext:FileUploadField ID="FileUploadField_Import" runat="server" Bu ...

  10. 区分Integer.getInteger和Integer.valueOf、Integer.parseInt() 的使用方法

    Integer类有两个看起来很类似的静态方法,一个是Integer.getInteger(String),另外一个是Integer.valueOf(String).如果只看方法名称的话,很容易将这两个 ...