前言
编写接口用例时,很多反向用例条件是一样的,例如:值为空、值为乱码、值为特殊字符等。
这些工作可以使用脚本实现,解放双手,提高效率。
目录
自动生成接口用例Excel文档
该脚本的本质是:按照接口用例的固定格式,把接口信息填写在对应的单元格里。
那么接口信息就需要使用者进行填写,如果接口很多,填写时不够方便;
可以再写一个脚本,辅助使用者填写接口信息。
所以一共需要填写两个脚本,
脚本一:辅助填写接口信息
脚本二:读取接口信息,并生成接口用例文档
脚本一:辅助填写接口信息
思路:
使用者把json格式的请求信息和响应结果,分别放到B1单元格和B2单元格;
脚本读取请求信息把参数名称和参数值读取出来,填写到sheet页的其他单元格里;
还有其他必须的接口信息,也填写到接口信息单元格里,并填入默认值;
最后使用者根据实际情况填入正确的接口信息。
另外,需要支持多个接口的填写,每个sheet页一个接口信息。
代码:
import json
import time
import openpyxl
# 输入接口信息
def interface(lujing):
interface_info = openpyxl.load_workbook(lujing) # 打开工作表
sheets = interface_info.worksheets # 获取所有工作簿
for sheet in sheets: # 遍历所有的工作簿,每个工作簿都需要辅助填写
sheet = interface_info[sheet.title] # 根据工作簿名称获取工作簿
value1 = sheet['B1'].value # 获取请求参数的值
value2 = json.loads(value1) # 将json值转换为字典
result = sheet['B2'].value # 获取返回结果的值
result1 = json.loads(result) # 将json值转换为字典
month = int(time.strftime('%m'))
day = int(time.strftime('%d'))
if day <= 8:
version = month + 0.1
elif 8 < day <= 22:
version = month + 0.2
else:
version = month + 1.1
# 填写内容
sheet['A4'].value = '接口名称'
sheet['B4'].value = 'XXXX接口'
sheet['A5'].value = '请求方式'
sheet['B5'].value = 'POST'
sheet['A6'].value = 'URL'
sheet['C4'].value = '成功状态码'
sheet['C5'].value = '失败状态码'
sheet['D5'].value = 400
sheet['C6'].value = '版本号'
sheet['D6'].value = version
sheet['A8'].value = '参数'
sheet['B8'].value = '参数1'
sheet['C8'].value = '值'
sheet['D8'].value = '是否必填'
# 读取返回的成功状态码 并填入,若没有默认200
if 'status' in result1:
sheet['D4'].value = result1['status']
else:
sheet['D4'].value = 200
# 把字典的参数和值放到列表中
i = 9 # 设定行数
for x, y in value2.items(): # 遍历请求参数字典
sheet["A" + str(i)].value = x # 把参数放到表格里
if isinstance(y, dict): # 判断值是否为字典
i += 1 # 行数+1
for a, b in y.items(): # 遍历字典
sheet["B" + str(i)].value = a # 参数放到表格里
sheet["C" + str(i)].value = b # 值放到表格里
sheet["D" + str(i)].value = '是' # 默认为必填
i += 1 # 行数+1
else:
sheet["C" + str(i)].value = y # 把值放到表格里
sheet["D" + str(i)].value = '是' # 默认为必填
i += 1 # 行数+1
interface_info.save(lujing) # 保存
if __name__ == '__main__':
lujing = '/Users/practice/工作簿2.xlsx'
interface(lujing)
脚本二:读取接口信息,并生成接口用例文档
思路:
首先获取接口信息文档中的信息;
把用例文档的表头填写好,调整好列宽;
填写正向用例,把相应的正向用例信息填入单元格;
填写反向用例,考虑值为空、值为null、值为乱码、值为其他类型参数的情况;
其中需要考虑两层json的情况
代码:
import json
import openpyxl
# import requests as requests
from openpyxl.styles import Alignment
from openpyxl.styles import Font
def interfaceCase(lujing, lujing_info):
# 创建接口用例文档
interface_case = openpyxl.Workbook(lujing) # 创建接口用例文档
# 从接口信息文档中获取数据
interface_info = openpyxl.load_workbook(lujing_info) # 打开接口信息文档
sheets = interface_info.worksheets # 获取所有的sheet页
for info_sheet in sheets: # 获取每个sheet页,并遍历
# info_sheet = interface_info.active # 获取接口信息默认sheet页
title1 = info_sheet['B4'].value[0:-2] # 名称
request_method = info_sheet['B5'].value+'\n'+info_sheet['B6'].value # 前提条件,请求方式+URL
base_url = info_sheet['B6'].value
request_parameters = info_sheet['B1'].value # 具体步骤,请求参数
Response = info_sheet['B2'].value # 预期结果,响应结果
status = str(info_sheet['D5'].value) # 需要获取异常状态码
status_code = str(info_sheet['D4'].value) # 需要获取正常状态码
version = str(info_sheet['D6'].value) # 获取版本号
# 创建sheet页
interface_case.create_sheet(title1)
interface_case.save(lujing) # 保存接口用例文档
# 打开文档
interface_case = openpyxl.load_workbook(lujing) # 打开接口用例文档
sheet = interface_case[title1]
# 输入表头
sheet['A1'].value = '名称'
sheet['B1'].value = '优先级'
sheet['C1'].value = '类型'
sheet['D1'].value = '开始版本'
sheet['E1'].value = '前提条件'
sheet['F1'].value = '具体步骤'
sheet['G1'].value = '预期结果'
sheet['H1'].value = '备注'
sheet['I1'].value = '标签'
sheet['J1'].value = 'RD结论'
sheet['K1'].value = 'QA结论'
# 编写正向用例
sheet['A2'].value = title1+'-正向'
sheet['B2'].value = '最高(0)'
sheet['C2'].value = '手工用例'
sheet['D2'].value = version
sheet['E2'].value = request_method
sheet['E2'].alignment = Alignment(wrapText=True) # 防止openpyxl修改样式,保持换行格式
parameters = json.loads(request_parameters)
parameters_new = json.dumps(parameters, ensure_ascii=False, indent=4)
sheet['F2'].value = parameters_new # 写入调整格式后的json
sheet['F2'].alignment = Alignment(wrapText=True)
Response1 = json.loads(Response)
Response_new = json.dumps(Response1, ensure_ascii=False, indent=4)
sheet['G2'].value = Response_new
sheet['G2'].alignment = Alignment(wrapText=True)
# 正向用例字体颜色调整为红色
font = Font(name='宋体', color='ff3300')
for i in range(1, 8):
sheet.cell(2, i).font = font
# 设置列宽
sheet.column_dimensions['A'].width = 35
sheet.column_dimensions['F'].width = 35
sheet.column_dimensions['G'].width = 35
sheet.column_dimensions['B'].width = 10
sheet.column_dimensions['C'].width = 10
sheet.column_dimensions['D'].width = 10
sheet.column_dimensions['E'].width = 45
def reverse_cases(case_name='为NULL-异常', value=None): # 第一层参数反向用例
sheet['A' + i] = title1 + '-' + row[0] + case_name
sheet['B' + i] = '中高(1)'
sheet['C' + i] = '手工用例'
sheet['D' + i] = version
sheet['E' + i] = request_method
sheet['E' + i].alignment = Alignment(wrapText=True)
# 编辑参数的值
parameters = json.loads(request_parameters)
parameters[row[0]] = value
parameters_new = json.dumps(parameters, indent=4, ensure_ascii=False)
sheet['F' + i] = parameters_new # 具体步骤——请求参数
sheet['F' + i].alignment = Alignment(wrapText=True)
if row[3] == '是' and value is None: # 必填 且 值为null 提示参数为必填
sheet['G' + i] = 'status为' + status + ',' + row[0] + '为必填项'
elif row[3] == '否' and value is None: # 非必填 且 值为null 正确显示返回值
sheet['G' + i] = '1、status为' + status_code + ',操作成功' + '\n' + '2、返回值与mrd定义一致'
sheet['G' + i].alignment = Alignment(wrapText=True) # 防止openpyxl修改样式,保持换行格式
else: # 非null且必填 非null且非必填 提示参数错误
sheet['G' + i] = 'status为' + status + ',' + row[0] + '参数异常'
# 发起post请求,根据响应状态码判断是否通过,并且填写QA结论
# result = requests.post(url=base_url, data=parameters_new)
# if result.status_code == status:
# sheet['K' + i] = 'pass'
# else:
# sheet['K' + i] = 'fail'
def reverse_cases_two(case_name='为NULL-异常', values=None): # 第二层参数反向用例
sheet['A' + i] = title1 + '-' + row[1] + case_name
sheet['B' + i] = '中高(1)'
sheet['C' + i] = '手工用例'
sheet['D' + i] = version
sheet['E' + i] = request_method
sheet['E' + i].alignment = Alignment(wrapText=True)
# 编辑参数的值
parameters = json.loads(request_parameters)
for key, value in parameters.items(): # 循环遍历字典
if isinstance(value, dict): # 判断字典中的值是否为字典
if row[1] in value: # 是字典,再判断第二个参数是否在这个字典里
value[row[1]] = values # 在字典里,对这个参数进行赋值
parameters_new = json.dumps(parameters, indent=4, ensure_ascii=False)
sheet['F' + i] = parameters_new # 具体步骤——请求参数
sheet['F' + i].alignment = Alignment(wrapText=True)
if row[3] == '是' and values is None: # 必填 且 值为null 提示参数为必填
sheet['G' + i] = 'status为' + status + ',' + row[1] + '为必填项'
elif row[3] == '否' and values is None: # 非必填 且 值为null 正确显示返回值
sheet['G' + i] = '1、status为' + status_code + ',操作成功' + '\n' + '2、返回值与mrd定义一致'
sheet['G' + i].alignment = Alignment(wrapText=True) # 防止openpyxl修改样式,保持换行格式
else: # 非null且必填 非null且非必填 提示参数错误
sheet['G' + i] = 'status为' + status + ',' + row[1] + '参数异常'
# 发起post请求,根据响应状态码判断是否通过,并且填写QA结论
# result = requests.post(url=base_url, data=parameters_new)
# if result.status_code == status:
# sheet['K' + i] = 'pass'
# else:
# sheet['K' + i] = 'fail'
# 编写异常用例
i = 3 # 设置当前行数interfaceCase
for row in list(info_sheet.values)[8:]: # 遍历interfaceInfo的接口信息
i = str(i)
# 第四个单元格有值,做进一步判断(有值说明是值不是字典,没有值说明该值为字典)
if row[3]:
# 第一个参数有值,使用第一个参数填写用例
if row[0]:
# 第一个反向用例:不输入该参数-异常
sheet['A'+i] = title1+'-'+row[0]+'为空-异常'
sheet['B'+i] = '中高(1)'
sheet['C'+i] = '手工用例'
sheet['D'+i] = version
sheet['E'+i] = request_method
sheet['E'+i].alignment = Alignment(wrapText=True)
# 移除字典中的值
parameters = json.loads(request_parameters)
parameters.pop(row[0])
parameters_new = json.dumps(parameters, indent=4, ensure_ascii=False)
sheet['F' + i] = parameters_new # 具体步骤——请求参数
sheet['F' + i].alignment = Alignment(wrapText=True)
if row[3] == '是': # 判断该参数是否为必填项
sheet['G' + i] = 'status为' + status + ',' + row[0] + '为必填项'
else:
sheet['G' + i] = '1、status为' + status_code + ',操作成功' + '\n' + '2、返回值与mrd定义一致'
sheet['G' + i].alignment = Alignment(wrapText=True) # 防止openpyxl修改样式,保持换行格式
# 该参数第一个反向用例写入完成,换行写入第二条反向用例,为null-异常
i = int(i)
i += 1
i = str(i)
reverse_cases('为null-异常', None)
# 该参数第二个反向用例写入完成,换行写入第三条反向用例,为乱码-异常
i = int(i)
i += 1
i = str(i)
reverse_cases('为乱码-异常', '5rhGF325b2Zsq2c3AX8KXI6YFiXg1')
# 该参数第三个反向用例写入完成,换行写入第四条反向用例,为其他类型参数-异常
i = int(i)
i += 1
i = str(i)
if type(row[2]) == float:
input_value = str("字符串类型")
elif type(row[2]) == int:
input_value = str("字符串类型1")
elif type(row[2]) == str:
input_value = 500
reverse_cases('为其他类型参数-异常', input_value)
# 第一个参数没有值,使用第二个参数填写用例
else:
sheet['A' + i] = title1 + '-' + row[1] + '为空-异常'
sheet['B' + i] = '中高(1)'
sheet['C' + i] = '手工用例'
sheet['D' + i] = version
sheet['E' + i] = request_method
sheet['E' + i].alignment = Alignment(wrapText=True)
# 移除嵌套字典中的值
parameters = json.loads(request_parameters)
for key, value in parameters.items(): # 循环遍历字典
if isinstance(value, dict): # 判断字典中的值是否为字典
if row[1] in value: # 是字典,再判断第二个参数是否在这个字典里
value.pop(row[1]) # 在字典里,就移除这个参数
parameters_new = json.dumps(parameters, indent=4)
sheet['F' + i] = parameters_new # 具体步骤——请求参数
sheet['F' + i].alignment = Alignment(wrapText=True)
if row[3] == '是': # 判断该参数是否为必填项
sheet['G' + i] = 'status为'+status+','+row[1]+'为必填项'
else:
sheet['G' + i] = '1、status为'+status_code+',操作成功'+'\n'+'2、返回值与mrd定义一致'
sheet['G' + i].alignment = Alignment(wrapText=True) # 防止openpyxl修改样式,保持换行格式
# 该参数第一个反向用例写入完成,换行写入第二条反向用例,为null-异常
i = int(i)
i += 1
i = str(i)
reverse_cases_two('为null-异常', None)
# 该参数第二个反向用例写入完成,换行写入第三条反向用例,为乱码-异常
i = int(i)
i += 1
i = str(i)
reverse_cases_two('为乱码-异常', '5rhGF325b2Zsq2c3AX8KXI6YFiXg1')
# 该参数第三个反向用例写入完成,换行写入第四条反向用例,为其他类型参数-异常
i = int(i)
i += 1
i = str(i)
if type(row[2]) == float:
input_value = str("字符串类型")
elif type(row[2]) == int:
input_value = str("字符串类型1")
elif type(row[2]) == str:
input_value = 500
reverse_cases_two('为其他类型参数-异常', input_value)
i = int(i)
i += 1 # 设置当前行数
# 保存工作表
interface_case.save(lujing)
if __name__ == '__main__':
# lujing 接口用例 生成地址+文件名称
# lujing_info 接口信息文档 地址+文件名称
lujing = '/Users/v_wangaiguo/Documents/practice/工作簿2测试用例.xlsx'
lujing_info = '/Users/v_wangaiguo/Documents/practice/interfaceInfo模板.xlsx'
interfaceCase(lujing=lujing, lujing_info=lujing_info)
资源下载
想要直接拿来用的同学,可以直接下载,里面有具体的操作说明