来源:《全栈 UI 自动化测试实战》一书中讲解的框架及案例代码实现:
一、框架结构:
本示例框架共分为 5 个组成模块:
① bin(运行管理模块)
② case(用例管理模块)
③ data(数据存储模块)
④ report(结果返回模块)
⑤ utils(功能扩展模块)

框架.png

框架展开.png
二、案例:
以百度网页搜索页面和百度新闻搜索页面为例
代码实现:
代码使用的 sleep 时间强制等待是为了测试方便,实际应用最好不要使用。
代码格式化快捷键:command+option+L或 ctrl+alt+L
1.case 模块用例:
case 模块实现思路:
以百度网页搜索页面和百度新闻搜索页面为例,分别将搜索内容进行参数化处理。
- 实现百度新闻模块测试用例:
# 第九章------9.2 ------case 模块用例----实现百度新闻模块测试用例
# 第九章/test_baidu_new.py
import unittest
import ddt
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
from Chapter9.framework_unit.utils.excel_read import ParseExcel
# 导入 data 模块 test_data.xlsx中的测试数据
excelPath = './../data/test_data.xlsx'
sheetName = 'data_new'
excel = ParseExcel(excelPath,sheetName)
# 使用 ddt 方式循环导入数据
@ddt.ddt
class Test_Baidu_News(unittest.TestCase):
@classmethod
def setUpClass(self):
self.driver = webdriver.Firefox()
@classmethod
def tearDownClass(self):
self.driver.quit()
def setUp(self):
self.driver.get(url='https://news.baidu.com/')
sleep(2)
def tearDown(self):
pass
@ddt.data(* excel.getDataFromSheet())
def test_sou(self,data):
self.driver.find_element(By.ID,'ww').send_keys(data)
sleep(2)
self.driver.find_element(By.ID,'s_btn_wr').click()
sleep(2)
self.assertEqual('百度资讯搜索_'+data,self.driver.title)
if __name__ == '__main__':
unittest.main()
- 实现百度搜索模块测试用例:
# 第九章------9.2 ------case 模块用例----实现百度搜索模块测试用例
# 第九章/test_baidu_sou.py
import unittest
import ddt
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
from Chapter9.framework_unit.utils.excel_read import ParseExcel
from Chapter9.framework_unit.utils.log import Log
# 导入 data 模块 test_data.xlsx中的测试数据
excelPath = './../data/test_data.xlsx'
# excelPath = './../data/test_data_sou.xlsx'
sheetName = 'data_sou'
excel = ParseExcel(excelPath,sheetName)
# 使用 ddt 方式循环导入数据
@ddt.ddt
class Test_Baidu_Search(unittest.TestCase):
'''百度搜索用例'''
@classmethod
def setUpClass(self):
self.driver = webdriver.Firefox()
self.log = Log()
@classmethod
def tearDownClass(self):
self.driver.quit()
def setUp(self):
self.driver.get(url='https://www.baidu.com/')
sleep(2)
def tearDown(self):
pass
@ddt.data(* excel.getDataFromSheet_mul())
def test_sou(self,data):
'''搜索方式'''
print("data[0]:", data[0])
try:
self.driver.find_element(By.ID,'chat-textarea').send_keys(data[0])
sleep(2)
self.driver.find_element(By.ID,'chat-submit-button').click()
sleep(2)
self.assertEqual(data[0]+'_百度搜索',self.driver.title)
print('try--assertEqual:---',data[0]+'_百度搜索',self.driver.title)
except AssertionError as e:
self.log.add_log(data[0],data[1],format(e))
self.assertEqual(data[0]+'_百度搜索',self.driver.title)
print('except--AssertionError--assertEqual:---',data[0]+'_百度搜索',self.driver.title)
else:
print('用例执行成功')
self.log.add_log(data[0],data[1],'用例执行成功')
if __name__ == '__main__':
unittest.main()
2. data 模块数据:
data模块实现思路:
data 模块以 Excel 文件作为数据管理媒介,在 Excel 文件中新建 data_sou和 data_new两张表,分别用来存放用例执行模块的搜索数据。Excel 存放数据表如下图:(sheet 名不要有空格)

图片1.png

图片.png
3. report 模块:
report模块实现思路:
report 模块中主要存放 3 种返回数据,分别是 HTML 结果页面、执行异常截图和执行过程日志记录
例如运行代码后生成的 log文件:

图片.png
4. uitls功能模块:
utils模块实现思路:
utils 模块主要用来存放一些框架运行过程中的辅助功能。
本章自动化测试框架中主要实现了 Excel表格数据的读取、初始化目录、日志记录功能。
-
数据读取功能:
Excel数据读取的讲解会在第 16 章数据驱动里进行详细演示。此处仅展示框架中数据读取功能的实现。
# 第九章---9.5---utils 功能模块---9.5.1 数据读取功能
# 第九章/excel_read.py
from openpyxl import load_workbook
class ParseExcel():
# 声明 ParseExcel 对象时传入 Excel 文件路径及表名
def __init__(self,excel_path,sheetName):
self.wb = load_workbook(excel_path)
self.sheet = self.wb[sheetName]
# 将表中数据处理成一维列表
# 此方法用来处理 data_new 表中数据
def getDataFromSheet(self):
dataList = []
for line in self.sheet:
dataList.append(line[0].value)
# 清空表头数据
dataList.pop(0)
return dataList
# 将表中数据处理成二维列表
# 将此方法用来处理 data_sou 表中数据
# 此方法适用于处理传入数据中自带预期数据情况
def getDataFromSheet_mul(self):
dataList = []
for line in self.sheet:
tmp_list = []
tmp_list.append(line[0].value)
tmp_list.append(line[1].value)
dataList.append(tmp_list)
dataList.pop(0)
return dataList
if __name__ == '__main__':
excel_path = './../data/test_data.xlsx'
sheetName = 'data_new'
pe = ParseExcel(excel_path,sheetName)
print(pe.getDataFromSheet())
-
初始化目录:
在 report 模块中记录返回数据时,首先会创建与日期同名目录,再将返回数据存在目录下面。
此方法通常用在所有用例开始执行前,具体使用方法见代码 run_all_case.py。
# 第九章 9.5.2 初始化目录
# 第九章/init_folder.py
import os
def init_folder(date):
# 创建 html 目录位置
html_folder_path = './../report/html/'
# 将所创建的子目录添加时间标记
folder_path = html_folder_path + date
# 判断当前日期目录是否存在,不存在则创建
if not os.path.exists(folder_path):
os.mkdir(folder_path)
# 创建 png 目录位置
png_folder_path = './../report/png/'
folder_path = png_folder_path + date
# 判断当前日期目录是否存在,不存在则创建
if not os.path.exists(folder_path):
os.mkdir(folder_path)
# 创建 log 目录位置
log_folder_path = './../report/log/'
folder_path = log_folder_path + date
# 判断当前目录是否存在,不存在则创建
if not os.path.exists(folder_path):
os.mkdir(folder_path)
-
日志记录功能
实现日志记录功能,代码如下:
# 第 9 章---9.5.3----日志记录功能
# 第九章/log.py
# logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
# level:设置日志级别
# format:指定handler使用的日志显示格式
# datefmt:指定日期时间格式,如果format参数中存在asctime,则需要指定时间格式
# filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中
# filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”
import logging
import datetime
class Log():
def __init__(self):
data = datetime.datetime.now().strftime('%Y-%m-%d')
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='./../report/log/' + data + '/test.log',
filemode='w'
)
def add_log(self, page,func,des):
out_str = page + ':' + func + ':' + des
logging.info(out_str)
5.bin 运行模块:
用例在执行时会根据具体情况选择执行部分或全部测试用例。
这种需求最快的实现方式是编写多个 run 文件,每个 run 文件的执行范围不同。
因为HTMLTestRunner下载失败,暂时不生成 html 了
- 创建执行范围为百度新闻模块用例的 run 文件:
# 第九章---9.6-----bin 运行模块----
# 第九章/run_new.py
import unittest
import datetime
from Chapter9.framework_unit.utils.init_folder import init_folder
dir = './../case/'
# 创建测试套件 suite
suite = unittest.TestLoader().discover(start_dir=dir, pattern='test_baidu_new.py')
if __name__ == '__main__':
date_time = datetime.datetime.now()
date = date_time.strftime('%Y-%m-%d')
report_time = date_time.strftime('%H:%M:%S')
init_folder(date)
# 创建测试套件运行器
runner = unittest.TextTestRunner()
# 调用 run()方法运行 suite 测试套件中的用例
runner.run(suite)
# # HTMLTestRunner 无法下载,且报错暂时不用------------
# import unittest
# import datetime
# import HTMLTestRunner
# from Chapter9.framework_unit.utils.init_folder import init_folder
#
# suite = unittest.defaultTestLoader.discover('./../case/',pattern='test_baidu_new.py')
#
# if __name__ == '__main__':
#
# date_time = datetime.datetime.now()
# date = date_time.strftime('%Y-%m-%d')
# report_time = date_time.strftime('%H%M%S')
# init_folder(date)
# fp = open('./../report/html/' + date + '/' + report_time + 'report.html', 'wb')
# runner = HTMLTestRunner.HTMLTestRunner(
# stream=fp,
# title='test.html',
# description='text')
# runner.run(suite)
# fp.close()
- 创建执行范围为百度新搜索模块用例的 run 文件:
# 第九章---9.6-----bin 运行模块----
#
# 第九章/run_sou.py
import unittest
import datetime
from Chapter9.framework_unit.utils.init_folder import init_folder
dir = './../case/'
# 创建测试套件 suite
suite = unittest.TestLoader().discover(start_dir=dir, pattern='test_baidu_sou.py')
if __name__ == '__main__':
date_time = datetime.datetime.now()
date = date_time.strftime('%Y-%m-%d')
report_time = date_time.strftime('%H:%M:%S')
init_folder(date)
# 创建测试套件运行器
runner = unittest.TextTestRunner()
# 调用 run()方法运行 suite 测试套件中的用例
runner.run(suite)
#
# # HTMLTestRunner 无法下载,且报错暂时不用------------------------
# import unittest
# import datetime
# import HTMLTestRunner
# from Chapter9.framework_unit.utils.init_folder import init_folder
#
# suite = unittest.defaultTestLoader.discover('./../case/',pattern='test_baidu_sou.py')
#
# if __name__ == '__main__':
#
# date_time = datetime.datetime.now()
# date = date_time.strftime('%Y-%m-%d')
# report_time = date_time.strftime('%H%M%S')
# init_folder(date)
# fp = open('./../report/html/' + date + '/' + report_time + 'report.html', 'wb')
# runner = HTMLTestRunner.HTMLTestRunner(
# stream=fp,
# title='text.html',
# description='text')
# runner.run(suite)
# fp.close()
- 创建执行范围为所有模块用例的 run 文件:
# 第九章---9.6-----bin 运行模块----
# 第九章/run_all-case.py
import unittest
import datetime
from Chapter9.framework_unit.utils.init_folder import init_folder
dir = './../case/'
# 创建测试套件 suite
suite = unittest.TestLoader().discover(start_dir=dir, pattern='test_baidu_*.py')
if __name__ == '__main__':
date_time = datetime.datetime.now()
date = date_time.strftime('%Y-%m-%d')
report_time = date_time.strftime('%H:%M:%S')
init_folder(date)
# 创建测试套件运行器
runner = unittest.TextTestRunner()
# 调用 run()方法运行 suite 测试套件中的用例
runner.run(suite)
# # HTMLTestRunner 无法下载,且报错暂时不用---------
# import unittest
# import datetime
# import HTMLTestRunner#下载失败,报错
# from Chapter9.framework_unit.utils.init_folder import init_folder
#
# suite = unittest.defaultTestLoader.discover('./../case/',pattern='test_baidu_*.py')
#
# if __name__ == '__main__':
#
# date_time = datetime.datetime.now()
# date = date_time.strftime('%Y-%m-%d')
# report_time = date_time.strftime('%H%M%S')
# init_folder(date)
# fp = open('./../report/html/' + date + '/' + report_time + 'report.html', 'wb')
# runner = HTMLTestRunner.HTMLTestRunner(
# stream=fp,
# title='test.html',
# description='text')
# runner.run(suite)
# fp.close()
6.运行结果显示:
以全部用例运行为例
(run_all-case.py)

所有用例运行结果.png
生成的日志log文件:

日志.png