Python+unittest+requests+HTMLTestRunner 完整的接口自动化测试框架搭建——框架结构简解
目录结构介绍
common:
——configEmail.py:这个文件主要是配置发送邮件的主题、正文等,将测试报告发送并抄送到相关人邮箱的逻辑。
——.run_method.py:这个文件主要来通过get、post、put、delete等方法来进行http请求,并拿到请求响应。
——HTMLTestRunner.py:主要是生成测试报告相关
——Logger.py:调用该类的方法,用来打印生成日志
——read_excel.py:操作Excel的方法
——get_path.py:获取项目绝对路径
——base_case.py:基础测试框架
——get_data:读取excel数据
——data_method:获取sheet用例个数,并遍历每个数字列表
config:
——read_Config.py:读取配置文件的方法,并返回文件中内容
——excel_config: 表格列名
——base_config.py:公共接口存取。例如:登录
——token.josn:获取的登录token存取处
data:
——config.ini:数据库、邮箱、接口等的配置项,用于方便的调用读取
——userCase.xlsx:设计测试用例,如参数为null,参数不正确等
log:
——logs:生成的日志文件
report:
——report.html:生成的测试报告
testCase:
——test_01_case.py:读取userCase.xlsx中的用例,使用base_case.py基础框架执行
RunAllCase.py:开始执行接口自动化,项目工程部署完毕后直接运行该文件即可
日志的输出,在一些关键的参数调用的地方我们来输出一些日志。从而更方便的来维护和查找问题。在common下创建Logger.py,内容如下
# coding:utf-8
import logging
import time
import os
class MyLogging:
def __init__(self):
timestr = time.strftime('%Y年%m月%d日%H时%M分%S秒', time.localtime(time.time()))
lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../logs'))
filename = lib_path + '/' + timestr + '.logs' # 日志文件的地址
self.logger = logging.getLogger() # 定义对应的程序模块名name,默认为root
self.logger.setLevel(logging.INFO) # 必须设置,这里如果不显示设置,默认过滤掉warning之前的所有级别的信息
sh = logging.StreamHandler() # 日志输出到屏幕控制台
sh.setLevel(logging.INFO) # 设置日志等级
fh = logging.FileHandler(filename=filename) # 向文件filename输出日志信息
fh.setLevel(logging.INFO) # 设置日志等级
# 设置格式对象
formatter = logging.Formatter(
"%(asctime)s %(filename)s[line:%(lineno)d]%(levelname)s - %(message)s") # 定义日志输出格式
# 设置handler的格式对象
sh.setFormatter(formatter)
fh.setFormatter(formatter)
# 将handler增加到logger中
self.logger.addHandler(sh)
self.logger.addHandler(fh)
if __name__ == "__main__":
log = MyLogging().logger
log.debug("debug")
log.info("info")
log.warning("warning")
log.error("error")
log.critical("critical")
然后创建ini文件,把接口中的一些参数抽取出并放到配置文件,然后通过一个读取配置文件的方法,方便后续的使用。同样还有邮件的相关配置~
##config.ini
# 域名管理,可能有多个端不同域名,目前分别识别为:app(用户)、web(老师)、admin(学校)
[HTTP]
app_baseurl = https://123456.com
web_baseurl = https://123456.com
admin_baseurl = https://123456.com
# 邮箱账号
[EMAIL]
smtp_server = smtp.qq.com
port = 465
sender = 123456@qq.com
password = ityjzdbxomnpjbgc
user_name = 123456@qq.com
receiver = 123456@qq.com
# 各端的登录账号,作为获取token取用
[PHONE]
app_user = SC17xiatest9
app_pwd = ZX123456
web_user = SC55061
web_pwd = ZX123456
admin_user = testone
admin_pwd = 123456
# 如有永久token的,可以放在这里使用
[TOKEN]
admin_token = 9205ff6e096b3a229b65e5daa01d80d5
app_token = 9205ff6e096b3a229b65e5daa01d80d5
web_token = 9205ff6e096b3a229b65e5daa01d80d5
接着读取ini,创建好read_Config.py
# coding:utf-8
import configparser
from common.get_path import *
import json
# 获取config.ini的路径
path = os.path.join(TESTCASE_PATH,"config.ini")
#读取配置文件config
config = configparser.ConfigParser()
config.read(path, encoding='utf-8')
class ReadConfig():
def get_http(self, name):
value = config.get('HTTP', name)
return value
def get_email(self, name):
value = config.get('EMAIL', name)
return value
def get_mysql(self, name):
value = config.get('DB_MYSQL', name)
return value
def get_account(self, name):
value = config.get('PHONE', name)
return value
def read_token(self,name):
value = config.get('TOKEN', name)
return value
def get_live_token(self, path):
with open(path, "r") as fp:
get_token = json.load(fp)
return get_token
# 测试是否成功读取到对应的配置
if __name__ == '__main__':
# print(ReadConfig().get_token(admin_token)['data']['token_type'])
print(ReadConfig().get_http('app_baseurl'))
print(ReadConfig().get_email('port'))
print(ReadConfig().get_mysql('user'))
print(ReadConfig().get_account('app_pwd'))
print(ReadConfig().read_token('app_token'))
配置文件与读取配置写好了,然后来根据接口设计几条简单的用例
用例设计完成后,继续往下,创建read_Excel.py
# coding:utf-8
import xlrd
from xlutils.copy import copy
import json
import xlwt
class ReadExcel():
"""封装操作excel表格方法"""
def __init__(self, flie_path, sheet_name):
self.flie_path = flie_path
self.sheet_name = sheet_name
self.workbook = xlrd.open_workbook(self.flie_path)
self.data = self.get_data()
# 为了在创建一个实例时就获得excel的sheet对象,可以在构造器中调用get_data()
# 获取某一页的sheet对象
def get_data(self):
data = xlrd.open_workbook(self.flie_path)
sheet = data.sheet_by_name(self.sheet_name)
return sheet
# 获取excel数据行数
def get_rows(self):
rows = self.data.nrows
return rows
# 获取某个单元格数据
def get_value(self, row, col):
"""
获取单元格数据
:param row: 行
:param col: 列
:return:
"""
value = self.data.cell_value(row, col)
return value
def get_cell_type(self, row, col):
"""
获取单元格数据的类型
:param row: 行
:param col: 列
:return:
"""
cell_type = self.data.cell_type(row, col)
# 0:空内容 1:字符集 2:数字 3:日期 4:布尔 5:错误
return cell_type
# 向某个单元格写入数据
def write_value(self,row, col, value):
"""
回写数据到excel
:param row:行
:param col:列
:param value:值
:return:
"""
data = xlrd.open_workbook(self.flie_path, formatting_info=True) # 打开文件
data_copy = copy(data) # 复制原文件
sheet = data_copy.get_sheet(self.sheet_name) # 取得复制文件的sheet对象
sheet.write(row, col, value) # 在某一单元格写入value
data_copy.save(self.flie_path) # 保存文件
if __name__ == '__main__':
test = ReadExcel("D:/test_api/data/初始用例.xls", "登录")
print(test.get_data())
excel_data = test.get_data()
print(excel_data.cell_value(1,4))
cell_data = eval(excel_data.cell_value(1, 4))
username = cell_data["username"]
# test.write_value(1, 7,"哈哈")
# print(test.get_value(1, 7))
# print(test.get_cell_type(1, 5))
print(test.get_cell_type(1, 4))
操作excel的完成了,继续创建excel_config.py,获取excel列元素
# coding:utf-8
# 根据索引,分别对应excel中的元素,若元素有改动,在这里维护即可
class Table(object):
test_id = 0
operating = 1
test_name = 2
url = 3
url_update = 4
run =