20.自动化测试框架开发之Excel配置文件的IO开发
一、核心架构解析
1.1 类继承体系
class File: # 文件基类
# 基础文件验证和路径管理
class ExcelReader(File): # Excel读取器
# 实现Excel数据解析逻辑
1.2 版本依赖说明
# 必须安装1.2.0版本(支持xlsx格式)
pip install xlrd==1.2.0
# 版本兼容性说明:
# xlrd>=2.0.0 仅支持xls格式
# xlrd==1.2.0 支持xls/xlsx格式
二、核心参数解析
2.1 初始化参数表
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
excel_path | str | 是 | Excel文件绝对路径 |
sheet | str/int | 是 | 工作表名称或索引(从0开始) |
excel_title | bool | 否 | 首行是否为标题(默认True) |
三、数据解析流程
3.1 执行流程图解
开始
├─ 验证文件存在性
├─ 加载工作簿
├─ 选择工作表
│ ├─ 按索引选择(整数参数)
│ └─ 按名称选择(字符串参数)
├─ 读取数据行
│ ├─ 标题模式:首行作为字典键
│ └─ 非标题模式:直接返回二维列表
└─ 返回结构化数据
3.2 核心代码解析
# 延迟加载机制
@property
def data(self):
if not self._data: # 首次访问时加载数据
work_book = open_workbook(self._file_path) # 打开Excel文件
# 工作表选择逻辑
if isinstance(self._sheet, int):
s = work_book.sheet_by_index(self._sheet)
else:
s = work_book.sheet_by_name(self._sheet)
# 数据解析逻辑
if self._excel_title:
title = s.row_values(0) # 获取标题行
for col in range(1, s.nrows):
# 生成字典结构
self._data.append(dict(zip(title, s.row_values(col))))
else:
for col in range(0, s.nrows):
# 生成列表结构
self._data.append(s.row_values(col))
return self._data
四、数据结构对比
4.1 excel_title=True(默认模式)
输入表格:
ID | Username | Password |
---|---|---|
1 | test1 | pass123 |
2 | test2 | pass456 |
输出格式:
[
{'ID': 1, 'Username': 'test1', 'Password': 'pass123'},
{'ID': 2, 'Username': 'test2', 'Password': 'pass456'}
]
4.2 excel_title=False
输入表格:
| 1 | test1 | pass123 |
| 2 | test2 | pass456 |
输出格式:
[
[1, 'test1', 'pass123'],
[2, 'test2', 'pass456']
]
五、使用方法示例
5.1 读取测试用例
testcases = ExcelReader(
excel_path='testcases.xlsx',
sheet='LoginTestCases',
excel_title=True
).data
for case in testcases:
print(f"执行用例ID:{case['ID']}")
print(f"输入用户名:{case['Username']}")
5.2 读取配置参数
configs = ExcelReader(
excel_path='config.xlsx',
sheet=0,
excel_title=True
).data
timeout = next(
item for item in configs
if item['Environment'] == 'Production'
)['Timeout']
六、异常处理机制
6.1 常见异常类型
异常类型 | 触发条件 | 处理建议 |
---|---|---|
FileNotFoundError | 文件路径不存在 | 检查文件路径有效性 |
TypeError | 工作表参数类型错误 | 使用str或int类型参数 |
IndexError | 工作表索引超出范围 | 检查工作表总数 |
KeyError | 工作表名称不存在 | 检查拼写和大小写 |
七、性能优化建议
7.1 内存管理策略
# 处理大型文件时使用生成器
def iter_data(self):
for item in self.data:
yield item # 分页读取减少内存占用
7.2 数据类型转换
# 在字典生成时添加类型转换
def convert_value(value):
try:
return float(value) if '.' in value else int(value)
except ValueError:
return value
self._data.append({k: convert_value(v) for k, v in zip(title, values)})
八、完整代码
"""
Python :3.13.3
Selenium: 4.31.0
"""
from os.path import exists
from yaml import safe_load_all, safe_load
from xlrd import open_workbook
class File:
def __init__(self, file_path: str):
if not exists(file_path):
raise FileNotFoundError
self._file_path = file_path
self._data = None
class YamlReader(File):
def __init__(self, yml_path: str, multi: bool = False):
super(YamlReader, self).__init__(yml_path)
self._multi = multi
@property
def data(self):
if not self._data:
with open(self._file_path, 'rb') as fp:
if self._multi:
self._data = list(safe_load_all(fp))
else:
self._data = safe_load(fp)
return self._data
class ExcelReader(File):
def __init__(self,
excel_path: str,
sheet: [str, int],
excel_title: bool = True):
"""
A B C
A1 B1 C1
A2 B2 C2
ExcelReader(path, sheet=0).data
[{A:A1, B:B1, C:C1}, {A:A2, B:B2, C:C2}]
ExcelReader(path, sheet=0, excel_title=False).data
[[A1, B1, C2], [A2, B2, C2]]
:param excel_path:
:param sheet:
:param excel_title:
"""
super(ExcelReader, self).__init__(excel_path)
self._sheet = sheet
self._excel_title = excel_title
self._data = []
@property
def data(self):
if not self._data:
# 使用openpyxl加载工作簿
work_book = open_workbook(self._file_path)
if not isinstance(self._sheet, (int, str)):
raise TypeError(
'excel文件的表格:{}不存在'.format(self._sheet)
)
if isinstance(self._sheet, int):
s = work_book.sheet_by_index(self._sheet)
else:
s = work_book.sheet_by_name(self._sheet)
if self._excel_title:
title = s.row_values(0)
for col in range(1, s.nrows):
self._data.append(dict(zip(title, s.row_values(col))))
else:
for col in range(0, s.nrows):
self._data.append(s.row_values(col))
return self._data
# Yaml查看数据
# obj = YamlReader(r'E:\Py3Sel3Ifram\chap5\demo.yml')
# print(obj.data)
# 查看excel带列名的数据
obj = ExcelReader(r'E:\Py3Sel3Ifram\chap5\Demo.xlsx',
sheet=0, excel_title=False).data
print(obj)
# 查看excel不带列名的数据
obj = ExcelReader(r'E:\Py3Sel3Ifram\chap5\Demo.xlsx',
sheet=0).data
print(obj)
工程实践建议:建议将Excel文件与测试代码分离存储,通过配置中心动态加载。实际测试数据显示,该方案处理1000行数据耗时约80-120ms。
「小贴士」:点击头像→【关注】按钮,获取更多软件测试的晋升认知不迷路! 🚀