前言:该框架总结自某学习网站的视频
一、 接口测试用例
运行前:
运行后:(10条通过,1条失败;通过即显示为pass,未通过则显示响应结果)
主要信息有:接口地址、请求类型、请求数据、预期结果、header和数据依赖,其中数据依赖是难点
二、封装操作excel的函数
创建文件 utils(文件夹名,下同)/operation_excel.py(文件名,下同)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import xlrd
from xlutils.copy import copy
class OperationExcel(object):
# 构造函数
def __init__(self, file_name=None, sheet_id=None):
# 如果指定表格信息,则使用指定的表格;若无指定,则使用默认的表格
if file_name:
self.file_name = file_name
self.sheet_id = sheet_id
else:
self.file_name = '../data/imooc_case.xls'
self.sheet_id = 0
self.sheet = self.get_sheet()
# 获取要操作的表格
def get_sheet(self):
table = xlrd.open_workbook(self.file_name)
sheet = table.sheets()[self.sheet_id]
return sheet
# 获取单元格的行数
def get_lines(self):
return self.sheet.nrows
# 获取单元格的列数
def get_cols(self):
return self.sheet.ncols
# 获取某个单元格的内容
def get_cell_value(self, row, col):
# 注意不要把小括号写成中括号
return self.sheet.cell_value(row, col)
# 写入数据
def write_value(self, 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)
# 获取某一列的内容
def get_cols_data(self, col_id=None):
if col_id != None:
cols = self.sheet.col_values(col_id)
else:
cols = self.sheet.col_values(0)
return cols
# 根据对应的case_id找到对应行的行号
def get_row_num(self, case_id):
num = 0
cols_data = self.get_cols_data()
for col_data in cols_data:
if case_id in col_data:
return num
num = num+1
# 根据行号,找到该行的内容
def get_row_values(self, row):
row_data = self.sheet.row_values(row)
return row_data
# 根据对应的case_id找到对应行的内容
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
三、 封装操作json文件(接口请求数据)方法
1、创建文件 data/user.json ,存储所有接口的请求数据。这些数据可以单个调式接口的时候,用fiddler搜集
2、创建文件 utils/operation_json.py
import json
class OperationJson(object):
def __init__(self, file_path=None):
if file_path == None:
self.file_path = '../data/user.json'
else:
self.file_path = file_path
self.data = self.read_data()
# 读取json文件
def read_data(self):
'''
load:针对文件句柄,将json格式字符转换成dict,从文件中读取
loads:针对内存对象,将string转换成dict
总结:不带s的是针对文件的操作,dumps同理
'''
with open(self.file_path) as file:
data = json.load(file)
return data
# 获取请求数据
def get_data(self, id):
values = self.data[id]
return values
# 写json
def write_data(self, data):
with open('../data/cookie.json', 'w') as file:
file.write(json.dumps(data))
四、 封装获取常量方法
创建文件 dataconfig/data_config.py
class GlobalVar(object):
'''
id,模块,url,是否运行,请求类型,是否携带header,case依赖,依赖的返回数据,
数据依赖字段,请求数据,预期结果、实际结果
'''
id = '0'
request_name = '1'
url = '2'
run = '3'
request_method = '4'
header = '5'
case_depend = '6'
data_depend = '7'
field_depend = '8'
data = '9'
expect = '10'
result = '11'
# 获取caseId
def get_id(self):
return GlobalVar.id
# 获取url
def get_url(self):
return GlobalVar.url
def get_run(self):
return GlobalVar.run
def get_request_method(self):
return GlobalVar.request_method
def get_header(self):
return GlobalVar.header
def get_case_depend(self):
return GlobalVar.case_depend
def get_data_depend(self):
return GlobalVar.data_depend
def get_field_depend(self):
return GlobalVar.field_depend
def get_data(self):
return GlobalVar.data
def get_expect(self):
return GlobalVar.expect
def get_result(self):
return GlobalVar.result
五、 封装获取接口数据方法
创建文件 dataconfig/get_data.py
from utils.operation_excel import OperationExcel
from utils.operation_json import OperationJson
from utils.connect_db import OperationMysql
from dataconfig.data_config import GlobalVar
class GetData(object):
def __init__(self):
self.opera_excel = OperationExcel()
self.global_val = GlobalVar()
# 获取case的个数
def get_case_lines(self):
return self.opera_excel.get_lines()
# 获取是否执行,把行数入参
def get_is_run(self, row):
# flag = None
col = int(self.global_val.get_run())
run = self.opera_excel.get_cell_value(row, col)
if run == "yes":
flag = True
else:
flag = False
return flag
# 是否携带header,携带的话直接返回header内容
def get_is_header(self, row):
col = int(self.global_val.get_header())
header = self.opera_excel.get_cell_value(row, col)
if header == "":
return None
return header
# 获取请求方式
def get_request_method(self, row):
col = int(self.global_val.get_request_method())
request_method = self.opera_excel.get_cell_value(row, col)
return request_method
# 获取url
def get_url(self, row):
col = int(self.global_val.get_url())
url = self.opera_excel.get_cell_value(row, col)
return url
# 获取请求数据
def get_request_data(self, row):
col = int(self.global_val.get_data())
data = self.opera_excel.get_cell_value(row, col)
if data == "":
return None
return data
# 通过获取关键字拿到data数据,从json文件中读取
def get_data_from_json(self, row):
opera_json = OperationJson()
data = opera_json.get_data(self.get_request_data(row))
return data
# 获取预期结果
def get_expect_data(self, row):
col = int(self.global_val.get_expect())
expect = self.opera_excel.get_cell_value(row, col)
if expect == "":
return None
return expect
# 通过sql获取预期结果
def get_expect_data_from_mysql(self, row):
opera_mysql = OperationMysql()
sql = self.get_expect_data(row)
result = opera_mysql.search_one(sql)
# decode('unicode-escape')反向编码字符成汉字
return result.decode('unicode-escape')
# 写入数据
def write_result(self, row, value):
col = int(self.global_val.get_result())
self.opera_excel.write_value(row, col, value)
# 判断是否有case依赖
def get_is_depend(self, row):
col = int(self.global_val.get_case_depend())
case_depend = self.opera_excel.get_cell_value(row, col)
if case_depend == "":
return None
return case_depend
# 获取依赖数据的key
def get_depend_key(self, row):
col = int(self.global_val.get_data_depend())
depend_key = self.opera_excel.get_cell_value(row, col)
if depend_key == "":
return None
return depend_key
# 获取数据依赖字段
def get_depend_field(self, row):
col = int(self.global_val.get_field_depend())
depend_field = self.opera_excel.get_cell_value(row, col)
if depend_field == "":
return None
return depend_field
六、 get和post基类的封装
创建文件 base/run_method.py
import requests
import json
class RunMethod(object):
def post_main(self, url, data, headers=None):
if headers != "None":
res = requests.post(url=url, data=data, headers=headers)
else:
res = requests.post(url=url, data=data)
# res.content.decode('utf8')
return res.json()
def get_main(self, url, data=None, headers=None):
if headers != None:
res = requests.get(url=url, data=data, headers=headers, verify=False)
else:
res = requests.get(url=url, data=data, verify=False)
return res.json()
def run_main(self, method, url, data=None, headers=None):
if method == "Post":
res = self.post_main(url, data, headers)
else:
res = self.get_main(url, data, headers)
# 因为json.dumps 序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False
return json.dumps(res, ensure_ascii=False)
# return json.dumps(res, ensure_ascii=False, sort_keys=True, indent=2)
七、预期结果和实际结果判断
创建文件 utils/common_util.py
import json
import operator
class CommonUtil(object):
# 判断一个字符串是否在另一个字符串中
def is_contain(self, str_one, str_two):
# isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()
'''
if isinstance(str_one, str):
str_one = str_one.encode("unicode-escape").decode("string-escape")
'''
flag = operator.contains(str_two, str_one)
return flag
八、 运行方法封装
创建文件 main/run_test.py
from base.run_method import RunMethod
from dataconfig.get_data import GetData
from utils.common_util import CommonUtil
class RunTest(object):
def __init__(self):
self.data = GetData()
self.run_method = RunMethod()
self.com_util = CommonUtil()
# self.send_mail = SendEmail()
# 执行程序
def go_on_run(self):
pass_count = []
fail_count = []
# 下标从0开始
rows_count = self.data.get_case_lines()
# 从下标1开始循环取数据,忽略第一行表头数据
for i in range(1, rows_count):
is_run = self.data.get_is_run(i)
if is_run:
method = self.data.get_request_method(i)
url = self.data.get_url(i)
# data = self.data.get_request_data(i)
data = self.data.get_data_from_json(i)
headers = self.data.get_is_header(i)
# expect = self.data.get_expect_data_from_mysql(i)
expect = self.data.get_expect_data(i)
res = self.run_method.run_main(method, url, data, headers)
if self.com_util.is_contain(expect, res):
self.data.write_result(i, 'pass')
pass_count.append(i)
else:
self.data.write_result(i, res)
fail_count.append(i)
print("成功的用例数:", len(pass_count))
print("失败的用例数:", len(fail_count))
# self.send_mail.send_main(pass_count, fail_count)
if __name__ == '__main__':
run = RunTest()
run.go_on_run()
运行结果: