You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
10 KiB
Python

4 months ago
import json
import re
from datetime import datetime
from PyQt5.QtCore import Qt, QTimer, QAbstractTableModel, QModelIndex, QPoint, QSize
from PyQt5.QtGui import QFont, QBrush, QColor
from openpyxl import load_workbook
class ExcelParser:
@staticmethod
def parseProcedure(filePath):
wb = load_workbook(filename=filePath)
if '测试脚本' in wb.sheetnames:
sheet = wb['测试脚本']
else:
sheet = wb.active
specInfo = {
3 months ago
"规程名称": sheet['B1'].value or "",
"规程编号": sheet['D1'].value or "",
"规程类型": sheet['F1'].value or ""
4 months ago
}
testCaseInfo = {
3 months ago
"测试用例": sheet['B2'].value or "",
"用例编号": sheet['D2'].value or "",
"工况描述": sheet['H2'].value or ""
4 months ago
}
testSteps = []
currentStep = None
stepCounter = 0
for rowIdx in range(5, sheet.max_row + 1):
cellA = sheet[f'A{rowIdx}'].value
cellB = sheet[f'B{rowIdx}'].value
cellC = sheet[f'C{rowIdx}'].value
if cellB is None and cellA is None:
continue
if cellA and re.match(r'STEP\d+[:]', str(cellA)):
if currentStep:
testSteps.append(currentStep)
stepCounter += 1
stepName = str(cellA).replace('', ':').strip()
4 months ago
stepDesc = str(cellB) if cellB else ""
4 months ago
currentStep = {
"步骤ID": stepName,
"步骤描述": stepDesc,
"操作类型": cellC if cellC else "",
"预期结果": sheet[f'D{rowIdx}'].value,
"子步骤": []
}
elif currentStep and cellA and str(cellA).isdigit():
subStep = {
"序号": int(cellA),
4 months ago
"操作": str(cellB) if cellB else "",
4 months ago
"操作类型": cellC if cellC else "",
"预期结果": sheet[f'D{rowIdx}'].value,
"实际结果": sheet[f'E{rowIdx}'].value,
"一致性": sheet[f'F{rowIdx}'].value if sheet[f'F{rowIdx}'].value == "" else "",
"测试时间": sheet[f'H{rowIdx}'].value,
"备注": sheet[f'I{rowIdx}'].value
}
currentStep["子步骤"].append(subStep)
if currentStep:
testSteps.append(currentStep)
return {
"文件路径": filePath,
3 months ago
"规程信息": {
"规程名称": specInfo["规程名称"],
"规程编号": specInfo["规程编号"],
"规程类型": specInfo["规程类型"]
},
"测试用例信息": {
"测试用例": testCaseInfo["测试用例"],
"用例编号": testCaseInfo["用例编号"],
"工况描述": testCaseInfo["工况描述"]
},
4 months ago
"测试步骤": testSteps
}
class StepTableModel(QAbstractTableModel):
columns = ['序号', '实验步骤','操作类型', '执行时间', '是否与预期一致', '实际结果', '备注']
4 months ago
def __init__(self, testSteps):
super().__init__()
self.stepData = []
self.stepIndex = 0
for mainStep in testSteps:
self.stepData.append({
'id': self.stepIndex,
'isMain': True,
'stepId': mainStep['步骤ID'],
'description': mainStep['步骤描述'],
'executed': False,
'stepType': mainStep['操作类型'],
4 months ago
'time': None,
'result': None,
3 months ago
'note': mainStep.get('备注', '') # 修复:从主步骤的备注字段读取
4 months ago
})
self.stepIndex += 1
for subStep in mainStep['子步骤']:
self.stepData.append({
'id': self.stepIndex,
'isMain': False,
'stepId': f"{mainStep['步骤ID']}{subStep['序号']}",
'description': subStep['操作'],
'stepType': subStep['操作类型'],
4 months ago
'executed': False,
'time': None,
'result': None,
'note': subStep['备注'] # 新增从Excel解析的备注字段
})
self.stepIndex += 1
def rowCount(self, parent=QModelIndex()):
return len(self.stepData)
def columnCount(self, parent=QModelIndex()):
return len(self.columns)
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
col = index.column()
step = self.stepData[row]
if role == Qt.DisplayRole:
if col == 0:
3 months ago
return step['stepId'] or ''
4 months ago
elif col == 1:
3 months ago
return step['description'] or ''
4 months ago
elif col == 2:
3 months ago
return step['stepType'] or ''
4 months ago
elif col == 3:
return step['time'].strftime("%Y-%m-%d %H:%M:%S") if step['time'] else ''
elif col == 4:
4 months ago
# print(step['result'])
4 months ago
if step['executed']:
if '失败' in step['result']:
return ''
else:
return ''
elif col == 5:
4 months ago
# print(step['result'])
3 months ago
return step['result'] or ''
elif col == 6:
4 months ago
return step['note'] if step['note'] else ''
elif role == Qt.BackgroundRole:
if step['executed']:
4 months ago
if '失败' in step['result']:
4 months ago
return QBrush(QColor(255, 182, 193))
4 months ago
else:
return QBrush(QColor(144, 238, 144))
4 months ago
elif step['isMain']:
return QBrush(QColor(220, 220, 220))
elif role == Qt.FontRole and step['isMain']:
font = QFont()
font.setBold(True)
return font
4 months ago
# 新增:支持自动换行
elif role == Qt.TextAlignmentRole:
if col in [1, 5]: # 描述和备注列
return Qt.AlignLeft | Qt.AlignVCenter
elif role == Qt.TextWordWrap:
if col in [1, 5]:
return True
4 months ago
return None
3 months ago
def flags(self, index):
"""返回单元格标志"""
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
return flags
4 months ago
def headerData(self, section, orientation, role):
if role == Qt.DisplayRole and orientation == Qt.Horizontal:
return self.columns[section]
return None
def getStepInfo(self, row):
if 0 <= row < len(self.stepData):
return self.stepData[row]
return None
def getFullStepInfo(self, row):
"""获取完整的步骤信息"""
if 0 <= row < len(self.stepData):
return self.stepData[row]
return None
def updateStepResult(self, row, result, time):
if 0 <= row < len(self.stepData):
4 months ago
# print(result)
4 months ago
self.stepData[row]['executed'] = True
self.stepData[row]['time'] = time
self.stepData[row]['result'] = result
self.dataChanged.emit(self.index(row, 0),
self.index(row, self.columnCount()-1),
[Qt.DisplayRole, Qt.BackgroundRole])
return True
return False
def resetExecutionState(self):
"""只重置执行状态(颜色),不清除时间和结果"""
for step in self.stepData:
step['executed'] = False
step['result'] = None
self.dataChanged.emit(self.index(0, 0),
self.index(self.rowCount()-1, self.columnCount()-1),
[Qt.BackgroundRole])
def resetAll(self):
"""完全重置所有状态(包括时间和结果)"""
for step in self.stepData:
step.update({
'executed': False,
'time': None,
'result': None
})
self.dataChanged.emit(self.index(0, 0),
self.index(self.rowCount()-1, self.columnCount()-1),
[Qt.DisplayRole, Qt.BackgroundRole])
3 months ago
def getTestSteps(self):
"""获取测试步骤数据,用于保存"""
testSteps = []
currentMainStep = None
for step in self.stepData:
if step['isMain']:
# 如果有前一个主步骤,先添加到结果中
if currentMainStep:
testSteps.append(currentMainStep)
# 创建新的主步骤
currentMainStep = {
'步骤ID': step['stepId'],
'步骤描述': step['description'],
'操作类型': step['stepType'],
'预期结果': '',
'子步骤': []
}
else:
# 子步骤
if currentMainStep:
# 从步骤ID中提取序号
stepId = step['stepId']
if currentMainStep['步骤ID'] in stepId:
subStepId = stepId.replace(currentMainStep['步骤ID'], '')
else:
subStepId = stepId
subStep = {
'序号': subStepId,
'操作': step['description'],
'操作类型': step['stepType'],
'预期结果': '',
'实际结果': step.get('result', ''),
'一致性': '' if step.get('result') and '失败' not in step.get('result', '') else '',
'测试时间': step.get('time', ''),
'备注': step.get('note', '')
}
currentMainStep['子步骤'].append(subStep)
# 添加最后一个主步骤
if currentMainStep:
testSteps.append(currentMainStep)
return testSteps