上次写的这个框架(如下),编写用例对编辑者的python能力有一定要求;用例如果是用Excel表格来维护,可以降低用例编写的门槛,可以增加这个自动化测试框架的维护效率。
目录
资源地址
不想看详细的编写过程,着急使用的小伙伴,可点下方链接,内附了完整框架资源和使用文档
https://download.youkuaiyun.com/download/python_problem/72603388
思路整理
- 在Excel表格中写入用例,每个sheet页写一条完整的测试用例,每行写一条操作步骤;
- 将表格中的内容读取出来;
- 根据每条操作的描述转化成python语言的文件,方便测试用例文件进行调用;
- 把读取的内容根据每个sheet页转化为对应的测试用例文件;
- 把这些用例添加到执行文件里的测试套件中;
- 最后执行“执行文件”。

改造过程
1.设计用例模版

- 序号/模块名称的填写需要与操作内容相符合
- 操作名称列:同一操作,必须是约定好的唯一的名称,便于以后转换为selenium操作
- 是否执行:填写yes/no,决定是否执行该操作,便于以后维护
- 元素定位方法:ID/ name/ class/ tagName/ linkText/ css/ xpath
- 元素定位路径:根据元素定位方法写入对应的路径
- 文本值:在输入值、判断等需要文本值的操作,填入对应文本
- 等待时间:需要等待时可填入等待时间(若为隐式等待也可不写等待操作)
2.表格中内容的读取
import openpyxl
def dataRead(lujing="../data/测试用例模板.xlsx"):
# 读取Excel
excel = openpyxl.load_workbook(lujing)
# 第一层字典 ------ 创建data空字典
data = {}
# 获取所有sheet页名称并进行遍历
for sheet_name in excel.sheetnames:
# 若sheet页名称包含test_case,就将这个sheet页赋给变量"sheet"
if "test_case" in sheet_name:
sheet = excel[sheet_name]
# 第二层字典 ------ 在data字典中,创建以sheet页名称为键的空字典
data[sheet_name] = {}
# 获取所有行的数据,并进行遍历
for row_data in sheet.rows:
# 第三层字典 ------ 创建以操作序号为键的空字典
data[sheet_name][row_data[0].value] = {}
# 第四层字典 ------ 内容放入键值对
data[sheet_name][row_data[0].value]['operation'] = row_data[2].value # 操作名称
data[sheet_name][row_data[0].value]['perform'] = row_data[3].value # 是否执行
data[sheet_name][row_data[0].value]['method'] = row_data[4].value # 元素定位方法
data[sheet_name][row_data[0].value]['path'] = row_data[5].value # 元素定位路径
data[sheet_name][row_data[0].value]['text'] = row_data[6].value # 文本值
data[sheet_name][row_data[0].value]['time'] = row_data[7].value # 等待时间
# 第一行为"序号"没有操作,需要移除;操作名称若为空没有操作,也需要移除
if not isinstance(row_data[0].value, int):
data[sheet_name].pop(row_data[0].value) # 移除表头
elif data[sheet_name][row_data[0].value]['operation'] is None:
data[sheet_name].pop(row_data[0].value) # 移除空操作
# 返回字典
return data
返回的字典数据为多个sheet页中的数据,格式如下:
{
'test_case03': {
1: {
'operation': '打开浏览器',
'perform': 'yes',
'method': None,
'path': None,
'text': 'https://www.baidu.com',
'time': None
},
2: {
'operation': '输入',
'perform': 'yes',
'method': 'xpath',
'path': '//*[@id="kw"]',
'text': '萝卜',
'time': None
},
......
},
'test_case04': {
1: {
'operation': '打开浏览器',
'perform': 'yes',
'method': None,
'path': None,
'text': 'https://www.baidu.com',
'time': None
},
......
}
}
3.字典数据转化为selenium操作
此处的“字典数据”为单个sheet页中的数据,格式如下:
{
1: {
'operation': '打开浏览器',
'perform': 'yes',
'method': None,
'path': None,
'text': 'https://www.baidu.com',
'time': None
},
2: {
'operation': '输入',
'perform': 'yes',
'method': 'xpath',
'path': '//*[@id="kw"]',
'text': '萝卜',
'time': None
},
......
}
字典数据转化为selenium操作的代码如下:
import time
from com.baidu.common.myUnit import MyUnit
from com.baidu.pageObject.pageObject import PageObject
from selenium.webdriver import ActionChains # 鼠标事件
from com.baidu.pages.dataRead import dataRead # 读取表格内容的方法
class DataPerform(PageObject):
# 将读取内容转化为selenium操作
def data_perform(self, case01):
# 创建空列表,用于存储判断结果
check_results = []
# 遍历数据并获取键名称(操作序号)
for operation_code in case01:
# 按照操作序号获取每一条操作数据
case02 = case01[operation_code]
# 是否执行为yes,才执行操作
if case02['perform'] == 'yes':
# 根据操作名称,执行对应的操作
if case02['operation'] == '打开浏览器':
self.driver.get(case02['text'])
elif case02['operation'] == '条件等待':
if case02['method'] == 'xpath':
percents = self.driver.find_element_by_xpath(case02['path']) # 加载进度
i = 1
while percents.text != case02['text']:
time.sleep(1)
if i == 90: # 最多等待20秒
break
i += 1
elif case02['operation'] == '等待':
time.sleep(case02['time'])
elif case02['operation'] == '判断':
if case02['method'] == 'xpath':
element = self.driver.find_element_by_xpath(case02['path'])
# 生成判断结果后,将结果存储在列表中
if element.text == case02['text']:
check_results.append(True)
else:
check_results.append(False)
elif case02['operation'] == '点击':
element = self.driver.find_element_by_xpath(case02['path'])
element.click()
elif case02['operation'] == '悬停':
element = self.driver.find_element_by_xpath(case02['path'])
ActionChains(self.driver).move_to_element(element).perform() # 鼠标悬浮在元素的中间
time.sleep(3)
elif case02['operation'] == '截屏':
self.screenShot(case02['text'])
elif case02['operation'] == '跳转新页面':
self.driver.close() # 关闭当前页签
# 切换窗口
n = self.driver.window_handles # 获取当前页所有窗口句柄
self.driver.switch_to.window(n[0]) # 切换到第一个
time.sleep(3)
elif case02['operation'] == '输入':
element = self.driver.find_element_by_xpath(case02['path'])
element.send_keys(case02['text'])
elif case02['operation'] == '打印':
element = self.driver.find_element_by_xpath(case02['path'])
print(element.text)
elif case02['operation'] == '清空':
element = self.driver.find_element_by_xpath(case02['path'])
element.clear()
# 遍历判断结果列表;列表中有false,就返回false;没有false,就不返回结果
for i in check_results:
if i is False:
return i
4.创建驱动文件
接下来需要:根据数据自动生成用例文件、自动将用例添加进测试套件中、自动启动运行器;由于这些操作都需要自动执行;所以需要创建一个驱动文件case_server.py
5.生成用例文件的方法
在驱动文件case_server.py中,写入生成用例文件的方法,根据数据批量生成用例文件
# 调用读取数据的方法
from com.baidu.pages.dataRead import dataRead
# 1.读取测试用例模板,每个sheet页,在test_cases文件夹下创建一个对应的TestCase文件
def createCaseFile():
data_dict = dataRead() # 获取测试用例模版数据字典
print(data_dict)
for case_name in data_dict: # 遍历第一层字典 --- 所有的sheet都要创建TestCase文件
print("用例名称:"+case_name)
# 文件名称 --- 以sheet页名称命名
file_name = '../test_cases/'+case_name+'.py'
# 给TestCase文件写入内容 --- 初始化页面对象时会调用DataPerform方法(数据转化为selenium操作的方法)
f = open(file_name, 'w')
f.write("""
from com.baidu.common.myUnit import MyUnit
from com.baidu.pages.dataPerform import DataPerform
from com.baidu.pages.dataRead import dataRead
class """ + case_name + """(MyUnit):
# 测试用例类里只需要编写 测试用例函数就可以
def test_01_home(self):
# 初始化页面对象
data_perform = DataPerform(self.driver)
# 取出数据
# data = home.readTable('../data/数据.xlsx','数据','A1')
# 调用逻辑函数
data_dict = dataRead()
case_name = '""" + case_name + """'
case01 = data_dict[case_name]
print(case01)
check_results = data_perform.data_perform(case01)
print(check_results)
if check_results is None:
check_results = True
# 断言判断
self.assertEqual(True, check_results)
""")
f.close()
6.将用例加入测试套件的方法(用例执行文件)
在驱动文件case_server.py中,写入生成run_test_case.py文件的方法,并把TestCase文件批量添加进测试套件里
# 2.在run_test_case文件夹下创建run_test_case.py文件,测试套件中套入TestCase文件
def createRunTestCase():
file = open('run_test_case.py', 'a')
data_dict = dataRead() # 获取测试用例模版数据字典
# print(data_dict)
for case_name in data_dict: # 遍历第一层字典 --- 所有的TestCase文件都引入运行文件中
# print("用例名称:" + case_name)
file.write("""
from com.baidu.test_cases.""" + case_name + """ import """ + case_name + """
""")
file.write("""
from com.baidu.run_test_case.HTMLTestRunnerX import HTMLTestRunner
import unittest
# 1 获取测试套件
suite = unittest.TestSuite()
# 2 测试套件中添加测试用例
""")
data_dict = dataRead() # 获取测试用例模版数据字典
print(data_dict)
for case_name in data_dict: # 遍历第一层字典 --- 所有的TestCase都添加到测试套件中
print("用例名称:" + case_name)
file.write("""
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(""" + case_name + """))
""")
file.write("""
# 3 获取运行器对象
f = open('../repots/baidu.html', mode='wb')
# stream报告存储位置 verbosity报告详细成都 title报告名称
runner = HTMLTestRunner(stream=f, verbosity=3, title='大屏首页标题测试报告')
# 4 生成测试报告
runner.run(suite)
""")
file.close()
7.执行运行文件的方法
在驱动文件case_server.py中,写入执行运行文件run_test_case.py的方法
import os
# 3.执行run_test_case.py文件
def implementRunTest():
os.system('python run_test_case.py')
8.恢复初始状态的方法
在驱动文件case_server.py中,写入删除/清空文件的方法;用例执行完毕后,可以删除生成的所有文件,恢复到开始的状态
import os
# 4.删除对应的TestCase文件,清空run_test_case.py文件,
def clearFile():
data_dict = dataRead() # 获取测试用例模版数据字典
# print(data_dict)
for case_name in data_dict: # 遍历第一层字典 --- 删除所有的TestCase文件
file_name = '../test_cases/' + case_name + '.py'
os.remove(file_name) # 删除对应的TestCase文件
# 清空run_test_case.py文件
file_run = open('./run_test_case.py', 'w')
file_run.write("""""")
9.进行测试
在驱动文件case_server.py中,调用四个方法:生成用例文件、将用例加入测试套件、执行运行文件、恢复初始状态,进行一次完整的测试
if __name__ == '__main__':
# 生成用例文件
createCaseFile()
# 将用例加入测试套件
createRunTestCase()
# 执行运行文件
implementRunTest()
# 恢复初始状态
clearFile()
框架的维护使用
1.在Excel表格中添加用例,sheet页签包含“test_case”为一条有效的测试用例,操作步骤的填写要求,见“改造过程第一点”;
2.在驱动文件case_server.py中,执行该文件。
本文介绍了一个使用Excel表格维护UI自动化测试用例的框架。通过设计特定的用例模板,读取Excel内容并转化为Selenium操作,实现了用例的自动化生成、执行和恢复初始状态。该方法降低了用例编写的门槛,提高了测试框架的维护效率。
1031

被折叠的 条评论
为什么被折叠?



