此框架是基于python的unittest单元测试框架写的。
先来看下框架的目录结构:
common :公共的方法目录
conf: 配置文件存放目录
data :测试数据目录
library :存放一些下载第三方的模块
logs:日志文件存放的目录
reports :测试报告存放目录
testcases:测试用例类模块目录
run_test.py:主程序,项目的启动文件
这里只需要把它们组合起来,然后通过各模块之间的调用,运行主程序来完成:读取excel用例数据、读取配置文件数据、ddt数据驱动自动获取用例、执行测试用例、生成日志文件,测试报告。
先看下common目录的构成:都是一些封装好的方法
all_paths.py
#这里把所有文件的目录路径都写在这里用变量接收,获取的时候直接调用变量就行。
import os
dir_name1=os.path.dirname(os.path.abspath(__file__))
dir_name=os.path.dirname(dir_name1)
log_path=os.path.join(os.path.join(dir_name,'logs'),'log.log')#log文件路径
casexlsx_path=os.path.join(os.path.join(dir_name,'data'),'case.xlsx')#测试用例excel文件路径
report_path=os.path.join(os.path.join(dir_name,'reports'),'report.html')#测试报告文件路径
config_path=os.path.join(os.path.join(dir_name,'conf'),'conf.yaml')#配置文件路径
case_path=os.path.join(dir_name,'testcases')#测试用例代码路径
excel_handler.py
#操作excel的方法,主要用于读取测试用例
import openpyxl
class ExcelMothed:
def __init__(self,filepath,sheet):
self.filepath=filepath
self.sheet=sheet
def open_excel(self):
'''打开excel'''
workbook=openpyxl.load_workbook(self.filepath)
return workbook
def get_sheet(self):
'''获取Sheet表单'''
workbook=self.open_excel()
sheet=workbook[self.sheet]
return sheet
def get_case(self):
'''获取所有用例'''
cell=self.get_sheet()
rows=list(cell.rows)
case=[]
title=[]
for row in rows[0]:
title.append(row.value)
for values in rows[1:]:
dic={}
for indx,value in enumerate(values):
dic[title[indx]]=value.value
case.append(dic)
return case
def excel_write(self,row,column,data):
'''excel根据单元格位置写入内容'''
sheet=self.get_sheet()
sheet.cell(row,column).value=data
self.excel_save()
self.excel_close()
def excel_save(self):
'''保存excel'''
self.open_excel().save(self.filepath)
def excel_close(self):
'''关闭excel'''
self.open_excel().close()
read_yaml.py
#读取yaml文件方法
import yaml
def read_yaml(file):
with open(file,encoding='utf-8') as f:
config_info=yaml.load(f,Loader=yaml.SafeLoader)
return config_info
logger_handler.py
#get_logger()的参数我放到了yaml文件里,所以需要从common里import read_yaml方法、配置文件的路径
import logging
from api_test_v1.common.read_yaml import read_yaml
from api_test_v1.common.all_paths import config_path
log_info=read_yaml(config_path)['log']
def get_logger(filepath=None,
fmtt=log_info['fmt'],
logger_level=log_info['logger_level'],
stream_level=log_info['stream_level'],
handler_level=log_info['file_level']):
logger = logging.getLogger() # 初始化收集器
# logger.handlers.clear()#清空收集器列表
if not logger.handlers:
logger.setLevel(logger_level)#设置日志等级
stream_handler=logging.StreamHandler()#初始化处理器
stream_handler.setLevel(stream_level)#设置处理器日志等级
logger.addHandler(stream_handler) # 处理器添加到收集器
fmt = logging.Formatter(fmtt) # 设置日志输出格式
stream_handler.setFormatter(fmt)# 添加到处理器
if filepath:
file_handler=logging.FileHandler(filepath,'a',encoding='utf-8')#初始化文件输出处理器
file_handler.setLevel(handler_level)#设置处理器日志等级
file_handler.setFormatter(fmt)
logger.addHandler(file_handler) # 处理器添加到收集器
return logger
配置文件内容如下:这里只是配置的日志方法里面用到的参数。
log:
fmt: '%(name)s--%(asctime)s--%(filename)s--%(lineno)d--%(levelname)s:%(message)s'
logger_level: 'DEBUG'
stream_level: 'DEBUG'
file_level: 'INFO'
data目录下的excel文件,存放的测试用例
library,生成测试报告的第三方模块
logs、reports目录,存放生成的日志、测试报告
testcases,测试用例代码,这里还以之前简单的login登录功能为例去写的测试用例
#登录功能
def login(username,password):
if username!=None and password!=None:
if username=='admin' and password=='123456':#账号密码正确登录成功
return {'msg':'登录成功'}
else:#账号密码错误
return {'msg':'账号或密码不正确'}
return {'msg':'账号或密码为空'}#账号或密码为空
from Testdemo.login import login#导入login函数
from api_test_v1.common.excel_handler import ExcelMothed#导入excel方法
from api_test_v1.common.all_paths import casexlsx_path,log_path#导入excel路径,日志路径
from api_test_v1.common.logger_handler import get_logger#导入日志方法
import unittest
import ddt#导入ddt,数据驱动模式
data=ExcelMothed(casexlsx_path,'Sheet1')#初始化
case=data.get_case()#获取用例
data.excel_close()#关闭excel
@ddt.ddt
class TestLogin(unittest.TestCase):#定义测试类继承unittest.TestCase类
@ddt.data(*case)
def test_login_success(self,cases):
info=eval(cases['data'])
username=info['username']
password=info['password']
expected_result=eval(cases['expected'])#预期结果
actual_result=login(username,password)#调用被测函数
try:
self.assertTrue(expected_result == actual_result) # 判断预期结果与实际结果是否一致
except Exception as e:
get_logger(log_path).info('用例未通过:{}'.format(e))#日志记录
raise e#手动抛出异常
else:
get_logger(log_path).debug('用例通过')#日志记录
run_test.py运行主程序代码如下:
import unittest
from api_test_v1.library.HTMLTestRunnerNew import HTMLTestRunner#导入第三方模块
from api_test_v1.common.all_paths import report_path,case_path#导入报告路径,测试用例的路径
loader=unittest.TestLoader()#初始化用例的加载器
test_suite=loader.discover(case_path)#自动加载测试用例
with open(report_path,'wb') as f:
runner=HTMLTestRunner(f,title='自动化测试报告',description='登录与注册模块',tester='tester')
runner.run(test_suite)#运行
最后运行主程序来看下日志及测试报告:
login--2020-06-03 14:10:00,138--test_login.py--23--INFO:用例未通过:False is not true
login--2020-06-03 14:10:00,139--test_login.py--26--INFO:用例通过
login--2020-06-03 14:10:00,140--test_login.py--26--INFO:用例通过