# -*- coding: utf-8 -*-
"""
Excel 数据加载模块
负责从 Excel 文件加载测试数据,处理数据转换和验证
"""
import json
from pathlib import Path
from typing import Dict, Any, List, Optional
from openpyxl import load_workbook, Workbook
from openpyxl.worksheet.worksheet import Worksheet
class ExcelDataLoader:
"""Excel 数据加载模块"""
def __init__(self, file_path: Path):
"""
初始化数据加载器
"""
self.file_path = Path(file_path)
if not self.validate_file():
raise FileNotFoundError(f"文件 {self.file_path} 不存在")
def validate_file(self) -> bool:
"""
验证文件是否存在
"""
return self.file_path.exists() and self.file_path.is_file()
def load_test_data(self, sheet_name: str) -> List[Dict[str, Any]]:
"""
加载测试数据
"""
try:
workbook = load_workbook(filename=self.file_path, data_only=True)
except Exception as e:
raise ValueError(f"无法加载文件 {self.file_path}:{e}")
if sheet_name not in workbook.sheetnames:
raise ValueError(f"文件 {self.file_path} 中不存在名为 {sheet_name} 的工作表")
sheet = workbook[sheet_name]
return self._parse_sheet_data(sheet)
def _parse_sheet_data(self, sheet: Worksheet) -> List[Dict[str, Any]]:
"""
解析工作表数据
"""
data_list = []
# 获取标题行(第一行)
headers = []
for cell in sheet[1]:
headers.append(cell.value if cell.value else "")
# 遍历数据行 (从第二行开始)
for row_idx, row in enumerate(sheet.iter_rows(min_row=2, values_only=True), start=2):
row_data = {}
for col_idx, (header, value) in enumerate(zip(headers, row)):
if header:
row_data[header] = value
# 转换数据类型
row_data = self.convert_data_types(row_data)
# 将数据添加到列表中
data_list.append(row_data)
print(f"加载数据行 {row_idx}:{json.dumps(row_data, ensure_ascii=False)}")
return data_list
def convert_data_types(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""
转换数据类型
自动转换数据类型
转换规则:
- 字符串 "null" → None
- JSON 字符串 → Dict/List
- 数字字符串 → int/float
- 空单元格 → None
- 布尔字符串 "true"/"false" → True/False
"""
converted = {}
for key, value in data.items():
converted[key] = self._convert_value(value)
return converted
def _convert_value(self, value: Any) -> Any:
"""
转换单个值
Args:
value: 原始值
Returns:
转换后的值
"""
# 空值处理
if value is None or value == '':
return None
# 字符串 "null" 转换为 None
if isinstance(value, str) and value.lower() == 'null':
return None
# 布尔字符串转换
if isinstance(value, str):
if value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
# JSON 字符串解析
if isinstance(value, str) and (value.startswith('{') or value.startswith('[')):
try:
return json.loads(value)
except json.JSONDecodeError:
# 不是有效的 JSON,保持原样
pass
# 数字字符串转换
if isinstance(value, str):
# 尝试转换为整数
try:
# 检查是否包含小数点
if '.' not in value:
return int(value)
except ValueError:
pass
# 尝试转换为浮点数
try:
return float(value)
except ValueError:
pass
# 保持原值
return value
def write_result(self, sheet_name: str, row_num: int, column_num: int, result: Any):
"""
写入测试结果
"""
try:
workbook = load_workbook(filename=self.file_path)
except Exception as e:
raise ValueError(f"无法加载文件 {self.file_path}:{e}")
if sheet_name not in workbook.sheetnames:
raise ValueError(f"文件 {self.file_path} 中不存在名为 {sheet_name} 的工作表")
sheet = workbook[sheet_name]
try:
sheet.cell(row=row_num, column=column_num).value = result
workbook.save(self.file_path)
print(f"写入结果到文件 {self.file_path} 成功")
return True
except Exception as e:
raise ValueError(f"无法写入结果到文件 {self.file_path}:{e}")
if __name__ == '__main__':
loader = ExcelDataLoader(Path(r"C:\Users\dujiale\PycharmProjects\TestApiFramework\data\supdatas.xlsx"))
data = loader.load_test_data("supinfor")
print(data)