# -*- coding: utf-8 -*- import logging LOG_FORMAT = "%(asctime)s>%(levelname)s>PID:%(process)d %(thread)d>%(module)s>%(funcName)s>%(lineno)d>%(message)s" logging.basicConfig( level=logging.DEBUG, format=LOG_FORMAT, ) # 是否打印调试信息标志 debug = True if debug: logging.debug("进入主程序,开始导入包...") # 导入常规库 import sys, re, string from pathlib import * # 导入word文档操作库 from win32com.client import DispatchEx from docxtpl import DocxTemplate import docx from docx import Document import shutil import pythoncom # 导入QT组件 from PyQt5 import QtCore from PyQt5.QtWidgets import QMainWindow, QFileDialog, QMessageBox, QDialog, QToolTip from PyQt5.QtCore import pyqtSignal from PyQt5.QtGui import QFont # 导入UI转换PY文件 from need.Ui_GUI import Ui_MainWindow from need import about, zhuan # 导入工具包文件-时间转换 from need.utils import get_current_time, get_current_name, get_current_date, get_current_hour from need.zhuan_tool import IEEE754_16_to_float, IEEE754_float_to_16 # 导入其他线程 from need.threads import create_bujian from need.fpga_record_thrend import create_FPGA_record from need.fpga_JtoS import create_FPGA_JtoS from need.new_JtoS import create_new_JtoS class zhuan_dlg(QDialog, zhuan.Ui_Dialog): def __init__(self): super().__init__() self.setupUi(self) if debug: logging.debug("初始化转换程序:") #linetext信号连接 self.lineEdit.editingFinished.connect(self.shiliu_zhuan) self.lineEdit_2.editingFinished.connect(self.shi_zhuan) # 设置气泡提示信息 QToolTip.setFont(QFont("SansSerif", 12)) self.lineEdit.setToolTip("注意,编辑输入框后需要点击其他控件才进行转换,且格式不正确不转换") self.lineEdit_2.setToolTip("注意,编辑输入框后需要点击其他控件才进行转换,且格式不正确不转换") def shiliu_zhuan(self): #获取当前文字 x = self.lineEdit.text() if len(x) == 8: if self.radioButton.isChecked() == True: #说明选中了32位转换 result = IEEE754_16_to_float(x, 32) self.lineEdit_2.setText(str(result)) elif len(x) == 16: if self.radioButton_2.isChecked() == True: #说明选中了64位转换 result = IEEE754_16_to_float(x, 64) self.lineEdit_2.setText(str(result)) def shi_zhuan(self): #获取当前文字 x = self.lineEdit_2.text() #字符串转浮点数 # if str.isdigit(x): # x = float(x) # elif str.isdigit(x.replace(".","")): try: x = float(x) except: logging.debug('输入的内容无法转换为浮点数') if isinstance(x, float) == True: print('进入转换函数里面') if self.radioButton.isChecked() == True: #说明选中了32位转换 result = IEEE754_float_to_16(x, 32) print(result) self.lineEdit.setText(str(result)) else: result = IEEE754_float_to_16(x, 64) self.lineEdit.setText(str(result)) class userMain(QMainWindow, Ui_MainWindow): #自定义信号和槽 def __init__(self): super().__init__() self.setupUi(self) if debug: logging.debug("初始化主程序:") # 实例化翻译家 self.trans = QtCore.QCoreApplication.translate self.setWindowTitle('测试个人工具') #使用翻译家改变PYQT的空间名字等属性self.label_4.setText(self.trans("MainWindow", "文件名(自动识别):")) if debug: logging.debug("初始化部分全局变量...") # 存放文件夹路径变量 self.open_dirs_name = '' # 存放文件名称路径变量 self.open_file_name = '' # 读取配置文件 #~~~~~~~~~~~~~~~连接线程函数~~~~~~~~~~~~~~~ ## 连接大纲生成说明函数 self.create_shuoming_trd = create_shuoming(self) self.create_shuoming_trd.sin_out.connect(self.text_display) self.pushButton_2.clicked.connect(self.create_shuoming_btn) ## 连接大纲追溯 self.create_dagang_zhuisu_trd = create_dagang_zhuisu(self) self.create_dagang_zhuisu_trd.sin_out.connect(self.text_display) self.pushButton_5.clicked.connect(self.creat_shuoming_zhuisu_btn) ## 连接说明追踪线程 self.create_shuoming_zhuisu_trd = create_shuoming_zhuisu(self) self.create_shuoming_zhuisu_trd.sin_out.connect(self.text_display) self.pushButton_6.clicked.connect(self.creat_dagang_zhuisu_btn) ## 连接报告追踪 self.create_baogao_zhuisu_trd = create_baogao_zhuisu(self) self.create_baogao_zhuisu_trd.sin_out.connect(self.text_display) self.pushButton_18.clicked.connect(self.create_baogao_zhuisu_btn) ## 连接单元追踪线程 self.create_danyuan_trd = create_danyuan(self) self.create_danyuan_trd.sin_out.connect(self.text_display) self.pushButton_8.clicked.connect(self.creat_danyuan_btn) ## 连接根据测试说明生成记录线程 self.create_jilu_trd = create_jilu(self) self.create_jilu_trd.sin_out.connect(self.text_display) self.pushButton_12.clicked.connect(self.creat_jilu_btn) ## 记录反向生成说明线程 self.create_shuomingfanxiang_trd = create_new_JtoS(self) self.create_shuomingfanxiang_trd.sin_out.connect(self.text_display) self.pushButton_13.clicked.connect(self.creat_shuomingfanxiang_btn) ## 自动填充空白表格线程 self.create_zidong_trd = create_zidong(self) self.create_zidong_trd.sin_out.connect(self.text_display) self.pushButton_15.clicked.connect(self.creat_zidong_btn) ## 清空单元格线程 self.clear_cell_trd = clear_cell(self) self.clear_cell_trd.sin_out.connect(self.text_display) self.pushButton_14.clicked.connect(self.clear_cell_btn) ## 提取表格内容线程 self.get_content_trd = get_content(self) self.get_content_trd.sin_out.connect(self.text_display) self.pushButton_19.clicked.connect(self.get_content_btn) ## 部件测试调用关系表格线程 self.create_bujian_trd = create_bujian(self) self.create_bujian_trd.sin_out.connect(self.text_display) self.pushButton_28.clicked.connect(self.create_bujian_btn) ## FPGA记录填写表格线程 self.create_FPGA_record_trd = create_FPGA_record(self) self.create_FPGA_record_trd.sin_out.connect(self.text_display) self.pushButton_30.clicked.connect(self.create_FPGA_record_btn) ## FPGA记录转为说明线程 self.create_FPGA_JtoS_trd = create_FPGA_JtoS(self) self.create_FPGA_JtoS_trd.sin_out.connect(self.text_display) self.pushButton_32.clicked.connect(self.create_FPGA_JtoS_btn) # 自定义信号连接 # 获取状态栏对象 self.user_statusbar = self.statusBar() # 右下角窗口尺寸调整符号 self.user_statusbar.setSizeGripEnabled(True) self.user_statusbar.setStyleSheet("QStatusBar.item{border:10px}") #~~~~~~~~~~~~~~~按钮连接函数~~~~~~~~~~~~~~~~ ##选择文件按钮连接 self.pushButton.clicked.connect(self.choose_docx_func) self.pushButton_4.clicked.connect(self.choose_docx_func) self.pushButton_7.clicked.connect(self.choose_docx_func) self.pushButton_11.clicked.connect(self.choose_docx_func) self.pushButton_16.clicked.connect(self.choose_docx_func) self.pushButton_17.clicked.connect(self.choose_docx_func) self.pushButton_27.clicked.connect(self.choose_docx_func) self.pushButton_29.clicked.connect(self.choose_docx_func) self.pushButton_31.clicked.connect(self.choose_docx_func) #清空显示区 self.pushButton_9.clicked.connect(self.clear_textEdit_content) #显示帮助 self.pushButton_10.clicked.connect(self.display_help) #~~~~~~~~~~~~~~~导航栏按钮连接函数~~~~~~~~~~~~~~~~ #显示关于本软件的菜单 self.actionAbout.triggered.connect(self.display_about) #打开文件夹 self.actionopen.triggered.connect(self.choose_docx_func) #打开IEEE754转换工具 self.actionIEEE754.triggered.connect(self.open_zhuan_tool) if debug: logging.debug("界面加载完成...") #~~~~~~~~~~~~~~~~~~~~初始化直接运行的函数(也就是起始运行一次)~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~间接按钮函数,用户点击后操作~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #清空显示区函数 def clear_textEdit_content(self): self.textBrowser.clear() return #显示帮助函数 def display_help(self): txt_path = Path.cwd() / 'need' / 'others' / 'readme.txt' with open(txt_path, 'r', encoding='utf-8') as f: data = f.read() self.textBrowser.append(data) return #显示关于函数 def display_about(self): dlg = QDialog() about_dlg = about.Ui_Dialog() about_dlg.setupUi(dlg) dlg.show() dlg.exec_() print("显示关于界面") return #显示IEEE754转换工具 def open_zhuan_tool(self): dlg_zhuan = zhuan_dlg() #实例化界面 dlg_zhuan.show() dlg_zhuan.exec_() return #~~~~~~~~~~~~~~~~~~~~线程区域函数,用于启动线程~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #生成测试说明启动函数 def create_shuoming_btn(self): self.create_shuoming_trd.start() self.tabWidget.setEnabled(False) return # 大纲追溯线程启动函数 def creat_dagang_zhuisu_btn(self): self.create_dagang_zhuisu_trd.start() self.tabWidget.setEnabled(False) # 说明追溯线程启动函数 def creat_shuoming_zhuisu_btn(self): self.create_shuoming_zhuisu_trd.start() self.tabWidget.setEnabled(False) # 提取单元格标题右侧内容线程启动函数 def create_baogao_zhuisu_btn(self): self.create_baogao_zhuisu_trd.start() self.tabWidget.setEnabled(False) # 记录反向生成说明线程 def creat_shuomingfanxiang_btn(self): self.create_shuomingfanxiang_trd.start() self.tabWidget.setEnabled(False) # 单元测试报告转换为我们的用例线程 def creat_danyuan_btn(self): self.create_danyuan_trd.start() self.tabWidget.setEnabled(False) # 单元测试报告转换为我们的用例线程 def creat_jilu_btn(self): self.create_jilu_trd.start() self.tabWidget.setEnabled(False) # 自动填充线程 def creat_zidong_btn(self): self.create_zidong_trd.start() self.tabWidget.setEnabled(False) # 清空表格单元格内容 def clear_cell_btn(self): self.clear_cell_trd.start() self.tabWidget.setEnabled(False) # 提取单元格标题右侧内容线程启动函数 def get_content_btn(self): self.get_content_trd.start() self.tabWidget.setEnabled(False) # 部件测试提取调用启动线程函数 def create_bujian_btn(self): self.create_bujian_trd.start() self.tabWidget.setEnabled(False) # FPGA记录填写 def create_FPGA_record_btn(self): self.create_FPGA_record_trd.start() self.tabWidget.setEnabled(False) # FPGA记录转说明 def create_FPGA_JtoS_btn(self): self.create_FPGA_JtoS_trd.start() self.tabWidget.setEnabled(False) #选择文档函数 def choose_docx_func(self): self.open_file_name = QFileDialog.getOpenFileName( self, '选择文件', '.', "Word files(*.docx)") self.textBrowser.append('已选择文件路径:' + self.open_file_name[0]) #关闭线程函数 def stop_shuoming_thread(self): self.tabWidget.setEnabled(True) QMessageBox.warning(self, '处理完毕', '文档处理完毕!') print("停止线程成功!") #~~~~~~~~~~~~~~~~~~~~显示函数~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def text_display(self, texttmp): if texttmp[:9] == 'stoperror': QMessageBox.warning(self, '处理完毕', '文档处理失败!') self.tabWidget.setEnabled(True) return if texttmp[:11] == 'stopsuccess': self.stop_shuoming_thread() self.tabWidget.setEnabled(True) return if texttmp[:6] == 'total:': cnt = int(texttmp[6:]) self.progressBar.setRange(0, cnt - 1) if texttmp == 'function success': QMessageBox.information(self, '操作成功', '请查看本程序当前文件夹下的相关文档!') self.textBrowser.append('完成!!!') self.tabWidget.setEnabled(True) return if texttmp == '保存文件错': QMessageBox.warning(self, '出错了', '保存文件失败!') self.tabWidget.setEnabled(True) return if texttmp == 'no folder': QMessageBox.information(self, '没有选择文件夹', '还没有选择文件夹,点击"文件"菜单进行选择!') self.tabWidget.setEnabled(True) return if texttmp.find('warning:') != -1: QMessageBox.information(self, 'WARNING', texttmp[8:]) self.tabWidget.setEnabled(True) return if texttmp.find('open failed:') != -1: QMessageBox.warning( self, '打开文件失败', '打开' + texttmp[12:] + '失败' + '请确认文档是否打开或者模板文件存在且后缀名为docx!') self.tabWidget.setEnabled(True) return if texttmp == 'nofile': QMessageBox.information(self, '错误', '还没有选择文件(夹),点击"文件"菜单或者工具栏进行选择!') self.tabWidget.setEnabled(True) return if texttmp.isdigit() == True: self.progressBar.setValue(int(texttmp)) self.tabWidget.setEnabled(True) else: self.textBrowser.append(texttmp) self.tabWidget.setEnabled(True) # 如果前面是all_doned:则进度条填满 if texttmp.find('all_doned:') != -1: self.progressBar.setRange(0, 100) self.progressBar.setValue(100) def closeEvent(self, event): reply = QMessageBox.question(self, '提示', "是否要关闭所有窗口?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() sys.exit(0) # 退出程序 else: event.ignore() ################################################################################## #大纲生成测试说明线程 ################################################################################## class create_shuoming(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): #用来储存测试项DC等转换 zhuan_dict = {'DC':'文档审查','SU':'功能测试','CR':'代码审查','SA':'静态分析','AC':'性能测试',\ 'IO':'接口测试','SE':'安全性测试','BT':'边界测试','RE':'恢复性测试','ST':'强度测试',\ 'AT':'余量测试','GUI':'人机交互界面测试','DP':'数据处理测试','JR':'兼容性测试',\ 'LG':'逻辑测试','AZ':'安装性测试','TT':'时序测试','PA':'功耗分析'} self.sin_out.emit("进入军品大纲转说明......") self.sin_out.emit("开始转换......") #如果没有选择路径则退出 if not self.parent.open_file_name: self.sin_out.emit('nofile') self.parent.tabWidget.setEnabled(True) return #告诉windows单线程 pythoncom.CoInitialize() #在用户选择的目录中查找大纲文档 self.sin_out.emit('打开测评大纲文档...') #使用win32com打开-记得关闭 #打开word应用 self.w = DispatchEx('Word.Application') #self.w.visible=True self.w.DisplayAlerts = 0 try: dagangfile = self.w.Documents.Open(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:选择的文档') self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return self.sin_out.emit('复制测试说明文档模板到本程序所在目录...') curpath = Path.cwd() / 'need' shuoming_path_tmp = curpath / 'document_templates' / '测试说明模板.docx' print(shuoming_path_tmp) if shuoming_path_tmp.is_file(): self.sin_out.emit('已检测到有说明模板文件...') else: self.sin_out.emit('open failed:选择的文档') return #创建一个字典来储存单个用例 data_list = [] #获取表格数量 try: csx_tb_count = dagangfile.Tables.Count self.sin_out.emit('total:' + str(csx_tb_count)) except: self.sin_out.emit('不存在表格!') QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格') try: dagangfile.Close() except: pass self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return #循环表格 yongli_count = 0 #用来储存章节号中的DC、SU等标识,用于章节号判断 is_fire_su = "" #用来储存基本_分割后个数 num_fenge = 3 for i in range(csx_tb_count): self.sin_out.emit(str(i)) if dagangfile.Tables[i].Rows.Count > 2: #注意win32com的Cell从1开始不是从0开始 if dagangfile.Tables[i].Cell(1, 1).Range.Text.find('测试项名称') != -1: #一个用例不变内容获取 dagangfile.Tables[i].Rows.First.Select() zhangjiehao = self.w.Selection.Bookmarks("\headinglevel").\ Range.Paragraphs(1).Range.ListFormat.ListString zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\ Range.Paragraphs(1).Range.Text.rstrip('\r') print("测试项所在章节号:", zhangjiehao) #获取用例标识不加上序号_1 basic_biaoshi = dagangfile.Tables[i].Cell( 1, 4).Range.Text.rstrip()[:-2] print("测试项标识为:", basic_biaoshi) #储存num_fenge的数值,初始化 if yongli_count == 0: num_fenge = len(basic_biaoshi.split("_")) #获取测试用例名称Cell(4,2)整行 info_ceshi_buzhou = dagangfile.Tables[i].Cell(4, 2).Range.Text info_ceshi_yuqi = dagangfile.Tables[i].Cell(9, 2).Range.Text #判断是否只有一行,如果只有一行处理表格 if dagangfile.Tables[i].Cell( 4, 2).Range.Paragraphs.Count <= 1: #缓存一个用例的data填入数据 data = {'zhangjie':'','mingcheng':'','biaoshi':'','is_first':'1', \ 'yueshu':'软件正常工作,环境连接正常', 'yongli_biaoshi':'','renyuan':'陈俊亦',\ 'chushi':'外接设备或软件运行正常','csx_mingcheng':'','is_begin':'0',\ 'zongsu':'',"zuhe":[],'csxbs':""} zuhe_dict = {"buzhou": "", "yuqi": "", "xuhao": "1"} try: #填写一行情况下表格 data['mingcheng'] = dagangfile.Tables[i].Cell( 1, 2).Range.Text.rstrip('\r\x07') #注意word中后面都有2个字符 data['yongli_biaoshi'] = (basic_biaoshi + "_1").replace( 'XQ', 'YL') data['zhangjie'] = zhangjiehao data['csx_mingcheng'] = zhangjieming data['biaoshi'] = basic_biaoshi data['zongsu'] = dagangfile.Tables[i].Cell( 3, 2).Range.Text[:-2] zuhe_dict["buzhou"] = dagangfile.Tables[i].Cell( 4, 2).Range.Text.rstrip('\r\x07') zuhe_dict["yuqi"] = dagangfile.Tables[i].Cell( 9, 2).Range.Text.rstrip('\r\x07') zuhe_dict["xuhao"] = '1' data["zuhe"].append(zuhe_dict) #判断是否为第一个测试类型,如果是修改章节号标识,则将章节号展示,如果和储存相同 #则章节号不展示 #首先获取测试项标识,分割成列表 fenge = data['biaoshi'].split("_") #获取当前测试项分割后的个数 if len(fenge) == 4: if fenge[-2] != is_fire_su: is_fire_su = fenge[-2] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[fenge[-2]] elif len(fenge) == 3: if fenge[-1] == 'DC' or fenge[ -1] == 'CR' or fenge[-1] == 'SA': if fenge[-1] != is_fire_su: is_fire_su = fenge[-1] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[fenge[-1]] else: if fenge[-2] != is_fire_su: is_fire_su = fenge[-2] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[fenge[-2]] else: if fenge[-1] != is_fire_su: is_fire_su = fenge[-1] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[fenge[-1]] if self.parent.lineEdit.text(): data['renyuan'] = self.parent.lineEdit.text() #将data加入data_list data['is_first'] = "1" data_list.append(data) yongli_count += 1 self.sin_out.emit( '###获取用例序号:{}'.format(yongli_count)) self.sin_out.emit('###该用例标识为:{}'.format( data['yongli_biaoshi'])) except: self.sin_out.emit( f'$$$$$$$$$$$$第{str(i+1)}个表格处理失败$$$$$$$$$$$$') pass elif dagangfile.Tables[i].Cell( 4, 2).Range.Paragraphs.Count > 1: try: #下面拆分每行,使用\r(回车)分割 info_buzhou_list = list( filter(lambda x: x != "\x07" and x != "", info_ceshi_buzhou.split('\r'))) info_yuqi_list = list( filter(lambda x: x != "\x07" and x != "", info_ceshi_yuqi.split('\r'))) #去掉括号和以下字符 rule = "[;;。]" #rule为去掉的符号(这个可以改TODO) #初始化去掉rule的列表 buzhou_list = [] yuqi_list = [] for item in info_buzhou_list: index = item.find("(") if index != -1: item = item[index + 1:] index = item.find("(") if index != -1: item = item[index + 1:] index = item.find(")") if index != -1: item = item[index + 1:] index = item.find(")") if index != -1: item = item[index + 1:] buzhou_list.append( re.sub(rule, "", item).lstrip(string.digits)) for item in info_yuqi_list: index = item.find("(") if index != -1: item = item[index + 1:] index = item.find("(") if index != -1: item = item[index + 1:] index = item.find(")") if index != -1: item = item[index + 1:] index = item.find(")") if index != -1: item = item[index + 1:] yuqi_list.append( re.sub(rule, "", item).lstrip(string.digits)) #获取测试项综述-为该循环前不变内容 basic_zongshu = buzhou_list.pop(0).strip() print('获取的测试用例综述是:', data["zongsu"]) #获取字典中的buzhou和yuqi,找冒号 j = -1 #自制列表索引 substrict_list = [] #差值列表 for item in buzhou_list: #先找到冒号所在索引 j = j + 1 if item.find(":") != -1 or item.find( ":") != -1: #现在知道冒号所在行号,现在要确定每个用例几行 substrict_list.append(j) #!!!注意差值计算步骤需要-1才是正确的步骤数量 # self.sin_out.emit("解析测试项序号"+ str(i) + "|检测到冒号所在行号为:" \ # + str(substrict_list)) # self.sin_out.emit("|检测到步骤总行数(序号):" \ # + str(len(buzhou_list))) #循环用例个数 count_test = len(substrict_list) temp_list = substrict_list temp_list.append(len(buzhou_list)) for item in range(count_test): #初始化data数据,包括步骤和预期、序号dict data = {'zhangjie':'','mingcheng':'','biaoshi':'','is_first':'0', \ 'yueshu':'软件正常工作,环境连接正常', 'yongli_biaoshi':'','renyuan':'陈俊亦',\ 'chushi':'外接设备或软件运行正常','csx_mingcheng':'','is_begin':'0',\ 'zongsu':'',"zuhe":[],'csxbs':""} #这里要求冒号最后一个 data['mingcheng'] = buzhou_list[ substrict_list[item]][:-1] data['yongli_biaoshi'] = ( basic_biaoshi + f'_{item+1}').replace( 'XQ', 'YL') #常规填入 data['zhangjie'] = zhangjiehao data['csx_mingcheng'] = zhangjieming data['biaoshi'] = basic_biaoshi data['zongsu'] = basic_zongshu #步骤填入,首先根据substrict_list获取有几个步骤 #循环行数 for x in range(temp_list[item + 1] - (temp_list[item] + 1)): #循环一个用例步骤预期数 zuhe_dict = { "buzhou": "", "yuqi": "", "xuhao": "" } #把每个步骤和预期都放进zuhe_dict中 zuhe_dict["buzhou"] = buzhou_list[ temp_list[item] + x + 1] zuhe_dict["yuqi"] = yuqi_list[ temp_list[item] + x + 1] zuhe_dict["xuhao"] = str(x + 1) data["zuhe"].append(zuhe_dict) if item == 0: data['is_first'] = '1' #判断是否为SU标题 fenge = data['biaoshi'].split("_") #获取当前测试项分割后的个数 if len(fenge) == 4: if fenge[-2] != is_fire_su: is_fire_su = fenge[-2] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[fenge[-2]] elif len(fenge) == 3: if fenge[-1] == 'DC' or fenge[ -1] == 'CR' or fenge[-1] == 'SA': if fenge[-1] != is_fire_su: is_fire_su = fenge[-1] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[ fenge[-1]] else: if fenge[-2] != is_fire_su: is_fire_su = fenge[-2] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[ fenge[-2]] else: if fenge[-1] != is_fire_su: is_fire_su = fenge[-1] data['is_begin'] = "1" data['csxbs'] = zhuan_dict[fenge[-1]] if self.parent.lineEdit.text(): data[ 'renyuan'] = self.parent.lineEdit.text( ) #加入data_list data_list.append(data) yongli_count += 1 #用例计数加一 self.sin_out.emit( '###获取用例序号:{}'.format(yongli_count)) self.sin_out.emit('###该用例标识为:{}'.format( data['yongli_biaoshi'])) except: self.sin_out.emit( f'$$$$$$$$$$$$第{str(i+1)}个表格处理失败$$$$$$$$$$$$') pass #关闭大纲文档(因为以及提取完毕) try: dagangfile.Close() self.w.Quit() pythoncom.CoUninitialize() except: self.sin_out.emit('function fail') self.w.Quit() pythoncom.CoUninitialize() return #打开模板文件进行渲染,然后就是用docxtpl生成用例 try: tpl_path = Path.cwd( ) / "need" / "document_templates" / "测试说明模板.docx" self.sin_out.emit('导入模板文件路径为:' + str(tpl_path)) tpl = DocxTemplate(tpl_path) #模板导入成功 except: QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确") return #开始渲染模板文件-有2层循环 try: context = { "tables": data_list, } tpl.render(context) tpl.save("生成的说明文档.docx") self.sin_out.emit('stopsuccess') except: self.sin_out.emit('stoperror') return ################################################################################## #大纲生成追踪关系 ################################################################################## class create_dagang_zhuisu(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): self.sin_out.emit("进入大纲追踪线程......") self.sin_out.emit("开始填写追踪......") #如果没有选择路径则退出 if not self.parent.open_file_name: self.sin_out.emit('nofile') self.parent.tabWidget.setEnabled(True) return #告诉windows单线程 pythoncom.CoInitialize() #在用户选择的目录中查找大纲文档 self.sin_out.emit('打开测评大纲文档...') #使用win32com打开-记得关闭 #打开word应用 self.w = DispatchEx('Word.Application') #self.w.visible=True self.w.DisplayAlerts = 0 try: dagangfile = self.w.Documents.Open(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:选择的文档') self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return curpath = Path.cwd() / 'need' zhuisu_path_tmp = curpath / 'document_templates' / '大纲追踪模板.docx' print(zhuisu_path_tmp) if zhuisu_path_tmp.is_file(): self.sin_out.emit('已检测到有追溯模板文件...') else: self.sin_out.emit('open failed:选择的文档') return #创建个列表放数据 data_list = [] data2_list = [] try: csx_tb_count = dagangfile.Tables.Count self.sin_out.emit('total:' + str(csx_tb_count)) except: self.sin_out.emit('不存在表格!') QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格') try: dagangfile.Close() except: pass self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return for i in range(csx_tb_count): self.sin_out.emit(str(i)) self.sin_out.emit("正在处理第{}个表格...".format(str(i))) print("正在处理第{}个表格...".format(str(i))) #准备填入的data data = { 'xuqiu': [], 'dg_zhangjie': '', 'mingcheng': '', 'biaoshi': '' } data2 = { 'xuqiu': [], 'dg_zhangjie': '', 'mingcheng': '', 'biaoshi': '' } if dagangfile.Tables[i].Rows.Count > 2: #注意win32com的Cell从1开始不是从0开始 if dagangfile.Tables[i].Cell(1, 1).Range.Text.find('测试项名称') != -1: #一个用例不变内容获取 dagangfile.Tables[i].Rows.First.Select() #获取测试项章节号 zhangjiehao = self.w.Selection.Bookmarks("\headinglevel").\ Range.Paragraphs(1).Range.ListFormat.ListString #获取测试项章节名 zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\ Range.Paragraphs(1).Range.Text.rstrip('\r') biaoshi = dagangfile.Tables[i].Cell( 1, 4).Range.Text.rstrip()[:-2] #获取需规的章节号和描述 if dagangfile.Tables[i].Cell( 2, 1).Range.Text.find("追踪关系") != -1: zhuizong_tmp = dagangfile.Tables[i].Cell( 2, 2).Range.Text[:-2] #由于有/的存在,先判断/和隐含需求 zhuizong_list = zhuizong_tmp.split("\r") print(zhuizong_list) if zhuizong_tmp == "/" or zhuizong_tmp == "隐含需求": xuqiu_dict = { 'xq_zhangjie': '/', 'xq_miaoshu': '/' } data['xuqiu'].append(xuqiu_dict) data2['xuqiu'].append(xuqiu_dict) else: if len(zhuizong_list) >= 1: for item in zhuizong_list: xuqiu_dict = {} if item.find("需求") != -1: try: match_string = re.search( "\d(.\d+)+", item).group() match_ming = item.split( match_string)[-1] xuqiu_dict[ 'xq_zhangjie'] = match_string xuqiu_dict[ 'xq_miaoshu'] = match_ming.lstrip( " ") data['xuqiu'].append(xuqiu_dict) except: self.sin_out.emit( f'$$$$$$$$$$$$第{str(i+1)}个表格无章节号$$$$$$$$$$$$' ) self.sin_out.emit( "转换终止!请检查表格中追踪关系有无章节号") pass else: try: match_string = re.search( "\d(.\d+)+", item).group() match_ming = item.split( match_string)[-1] xuqiu_dict[ 'xq_zhangjie'] = match_string xuqiu_dict[ 'xq_miaoshu'] = match_ming.lstrip( " ") data2['xuqiu'].append(xuqiu_dict) except: self.sin_out.emit( f'$$$$$$$$$$$$第{str(i+1)}个表格无章节号$$$$$$$$$$$$' ) self.sin_out.emit( "转换终止!请检查表格中追踪关系有无章节号") pass #如果追踪关系行数小于1行的情况 else: xuqiu_dict = { 'xq_zhangjie': '/', 'xq_miaoshu': '/' } data['xuqiu'].append(xuqiu_dict) data2['xuqiu'].append(xuqiu_dict) try: data['dg_zhangjie'] = zhangjiehao data['mingcheng'] = zhangjieming data['biaoshi'] = biaoshi data_list.append(data) data2['dg_zhangjie'] = zhangjiehao data2['mingcheng'] = zhangjieming data2['biaoshi'] = biaoshi data2_list.append(data2) except: print("获取追踪出错啦!") self.sin_out.emit( f'$$$$$$$$$$$$第{str(i+1)}个表格追踪处理失败$$$$$$$$$$$$' ) pass #最后关闭文档 try: self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) except: QMessageBox.warning(self.parent, "关闭文档失败", "关闭文档失败!") return try: tpl_path = Path.cwd( ) / "need" / "document_templates" / "大纲追踪模板.docx" self.sin_out.emit('导入模板文件路径为:' + str(tpl_path)) tpl = DocxTemplate(tpl_path) #模板导入成功 except: QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确") return #开始渲染模板文件 try: context = { "tables": data_list, "tables2": data2_list, } tpl.render(context) tpl.save("生成的大纲追踪文档.docx") self.sin_out.emit('stopsuccess') except: QMessageBox.warning(self.parent, "生成文档出错", "生成文档错误,请确认模板文档是否已打开或格式错误") self.sin_out.emit('stoperror') return ################################################################################## #单元测试UAS转换 ################################################################################## class create_danyuan(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): self.sin_out.emit("进入单元测试SunwiseAUnit转换线程......") self.sin_out.emit("开始填写文档......") #如果没有选择路径则退出 if not self.parent.open_file_name: self.sin_out.emit('nofile') self.parent.tabWidget.setEnabled(True) return #告诉windows单线程 pythoncom.CoInitialize() #在用户选择的目录中查找UAS单位测试报告文档 self.sin_out.emit('打开单元测试原文件...') #使用win32com打开-记得关闭 #打开word应用 self.w = DispatchEx('Word.Application') #self.w.visible=True self.w.DisplayAlerts = 0 try: danyuanfile = self.w.Documents.Open(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:选择的文档') self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return curpath = Path.cwd() / 'need' danyuan_file_tmp = curpath / 'document_templates' / 'SunwiseAUnit单元测试转换模板.docx' print(danyuan_file_tmp) if danyuan_file_tmp.is_file(): self.sin_out.emit('已检测到有追溯模板文件...') else: self.sin_out.emit('open failed:选择的文档') return #创建个列表放数据-important data_list = [] #try统计表格数量 try: csx_tb_count = danyuanfile.Tables.Count self.sin_out.emit('total:' + str(csx_tb_count)) self.sin_out.emit("正在调用word文档操作接口,可能会有点慢...") except: self.sin_out.emit('不存在表格!') QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格') try: danyuanfile.Close() except: pass self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return #开始处理表格-important #我先统计有多少个生成的表格-即用例有多少个呗 yongli_count = 0 for i in range(csx_tb_count): if danyuanfile.Tables[i].Rows.Count > 2: #注意win32com的Cell从1开始不是从0开始 if danyuanfile.Tables[i].Cell(1, 1).Range.Text.find('用例名称') != -1: yongli_count += 1 #yongli_num指向当前处理的用例 yongli_num = 0 hanshuming = '' hanshuming_duibi = '' wenjian = '' wenjian_duibi = '' for i in range(csx_tb_count): self.sin_out.emit('正在处理的表格序号:' + str(yongli_num + 1)) self.sin_out.emit(str(i)) #准备填入的data data = {'ruanjian_ming':'','ruanjian_biaoshi':'yongli_biaoshi','wenjian_ming':'',\ 'hanshu_ming':'','bianlian_and_canshu':'','zhuang':[],\ 'yuqi_jieguo':'','ceshi_jieguo':'','is_begin':'0','is_wenjian':'0'} #填入用户输入的软件名 try: data['ruanjian_ming'] = self.parent.lineEdit_2.text() data['ruanjian_biaoshi'] = self.parent.lineEdit_3.text() except: QMessageBox.critical(self.parent, "未填入数据", "请先填入软件名和软件标识或.C名称") self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) pass #找到函数名,这里容易出问题 if danyuanfile.Tables[i].Rows.Count > 2: if danyuanfile.Tables[i].Cell(1, 1).Range.Text.find('功能描述') != -1: danyuanfile.Tables[i].Cell(1, 1).Range.Select() self.w.Selection.MoveUp() self.w.Selection.MoveUp() self.w.Selection.MoveUp() s = self.w.Selection.Paragraphs(1).Range.Text[:-1] s1 = s.split(". ")[-1] #放入函数名比对 if s1 != hanshuming_duibi: hanshuming_duibi = s1 #再向上看1行 self.w.Selection.MoveUp() temp2 = self.w.Selection.Paragraphs(1).Range.Text[:-1] s2 = temp2.split("\\")[-1] if '.' in temp2 and '\\' in temp2: print('@@@@@@:', s2) if s2 != wenjian_duibi: #这里有改动 wenjian_duibi = s2 #找章节号 if danyuanfile.Tables[i].Rows.Count > 2: #注意win32com的Cell从1开始不是从0开始 if danyuanfile.Tables[i].Cell(1, 1).Range.Text.find('用例名称') != -1: #TODO:如何找到测试模块? biaoshi_temp = danyuanfile.Tables[i].Cell( 1, 4).Range.Text[:-2] data['yongli_biaoshi'] = biaoshi_temp #获取表格中参数组合() quanju = danyuanfile.Tables[i].Cell(5, 3).Range.Text[:-2] hcan = danyuanfile.Tables[i].Cell(6, 3).Range.Text[:-2] qitashu = danyuanfile.Tables[i].Cell(7, 3).Range.Text[:-2] if quanju.find('无') != -1: quanju = "" if hcan.find('无') != -1: hcan = "" if qitashu.find('无') != -1: qitashu = "" data['bianlian_and_canshu'] = quanju + hcan + qitashu #将预期结果和测试结果填入 data['yuqi_jieguo'] = danyuanfile.Tables[i].Cell( 8, 2).Range.Text[:-2] data['ceshi_jieguo'] = danyuanfile.Tables[i].Cell( 13, 2).Range.Text[:-2] #函数名获取 if hanshuming_duibi != hanshuming: hanshuming = hanshuming_duibi data['is_begin'] = '1' data['hanshu_ming'] = hanshuming_duibi #文件名获取 if wenjian_duibi != wenjian: wenjian = wenjian_duibi data['is_wenjian'] = '1' data['wenjian_ming'] = wenjian_duibi data_list.append(data) yongli_num += 1 #用例创建加一 elif danyuanfile.Tables[i].Cell(1, 2).Range.Text.find('定义') != -1: #定义个桩函数dict zhuang_dict = {'zhuang_name':'','zhuang_dingyi':'','zhuang_fanhui':'',\ 'zhuang_fuzuoyong':''} zhuang_dict['zhuang_name'] = danyuanfile.Tables[i].Cell( 1, 1).Range.Text[:-2] zhuang_dict['zhuang_dingyi'] = danyuanfile.Tables[i].Cell( 1, 3).Range.Text[:-2] zhuang_dict['zhuang_fanhui'] = danyuanfile.Tables[i].Cell(2, 3).Range.Paragraphs(1).\ Range.Text[:-1] #副作用可能有多行 fuzuoyong_temp = '' for count_fuzuo in range( len(danyuanfile.Tables[i].Cell( 2, 3).Range.Paragraphs) - 2): fuzuoyong_temp = fuzuoyong_temp + ';' + danyuanfile.Tables[i].Cell(2, 3).\ Range.Paragraphs(count_fuzuo + 3).Range.Text[:-2].replace(" ", "") zhuang_dict['zhuang_fuzuoyong'] = fuzuoyong_temp data_list[yongli_num - 1]['zhuang'].append(zhuang_dict) #最后关闭文档 try: self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) except: QMessageBox.warning(self.parent, "关闭文档失败", "关闭文档失败!") return try: tpl_path = Path.cwd( ) / "need" / "document_templates" / "SunwiseAUnit单元测试转换模板.docx" self.sin_out.emit('导入模板文件路径为:' + str(tpl_path)) tpl = DocxTemplate(tpl_path) #模板导入成功 except: QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确") return #开始渲染模板文件 try: context = { "tables": data_list, } tpl.render(context) tpl.save("软件单元测试用例记录表.docx") self.sin_out.emit('stopsuccess') except: self.sin_out.emit('stoperror') return ################################################################################## #测试说明追踪以及用例表 ################################################################################## class create_shuoming_zhuisu(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): self.sin_out.emit("进入说明追踪线程......") self.sin_out.emit("开始填写说明追踪以及用例表格......") # 如果没有选择文件 if not self.parent.open_file_name: self.sin_out.emit('nofile') self.parent.tabWidget.setEnabled(True) return # 告诉windows单线程 pythoncom.CoInitialize() # 在用户选择的目录中查找大纲文档 self.sin_out.emit('打开测试说明文档...') # 使用win32com打开-记得关闭 # 打开word应用 self.w = DispatchEx('Word.Application') # self.w.visible=True self.w.DisplayAlerts = 0 try: shuomingfile = self.w.Documents.Open(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:选择的文档') self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return self.sin_out.emit('已正确打开说明文档...') curpath = Path.cwd() / 'need' zhuisu_path_tmp = curpath / 'document_templates' / '说明追踪模板.docx' print("打开追踪模板文件", zhuisu_path_tmp) if zhuisu_path_tmp.is_file(): self.sin_out.emit('已检测到有说明追溯模板文件...') else: self.sin_out.emit('open failed:选择的文档') return # 创建个列表放数据 data_list = [] data2_list = [] #统计整个表格数量用于processbar显示进度 try: tb_count = shuomingfile.Tables.Count self.sin_out.emit('total:' + str(tb_count)) except: self.sin_out.emit('不存在表格!') QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格') try: shuomingfile.Close() except: QMessageBox.warning(self.parent, '错误', "未正确关闭Word文档!") return self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return #遍历循环表格,这里面就要初始化数据dict了 #不能像大纲追踪一样data在循环表格里面 #创建一个大纲测试项索引 csx_name = '' data = { 'dg_zhangjie': '', 'mingcheng': '', 'biaoshi': '', 'yongli': [], 'index': 0 } for i in range(tb_count): self.sin_out.emit(str(i)) #self.sin_out.emit("正在处理第{}个表格...".format(str(i+1))) print("正在处理第{}个表格...".format(str(i + 1))) # 准备填入的data data2 = { 'yongli_ming': '', 'yongli_biaoshi': '', 'yongli_zongsu': '' } yongli_dict = {'yongli_ming': '', 'yongli_biaoshi': ''} yongliming = '' biaoshi = '' zongsu = '' zhui_temp = '' if shuomingfile.Tables[i].Rows.Count > 2: try: # 注意win32com的Cell从1开始不是从0开始 if shuomingfile.Tables[i].Cell(1, 1).Range.Text.find('测试用例名称') != -1 or \ shuomingfile.Tables[i].Cell(2, 1).Range.Text.find('测试用例名称') != -1: #取出cell(1,,1)的数据 table_heard = shuomingfile.Tables[i].Cell(1, 1).Range.Text if table_heard.find("测试用例名称") != -1: yongliming = shuomingfile.Tables[i].Cell( 1, 2).Range.Text.rstrip()[:-2] biaoshi = shuomingfile.Tables[i].Cell( 1, 4).Range.Text.rstrip()[:-2] zongsu = shuomingfile.Tables[i].Cell( 3, 2).Range.Text.rstrip()[:-2] zhui_temp = shuomingfile.Tables[i].Cell( 2, 2).Range.Text.rstrip()[:-2] elif table_heard.find('用例') != -1: yongliming = shuomingfile.Tables[i].Cell( 2, 2).Range.Text.rstrip()[:-2] biaoshi = shuomingfile.Tables[i].Cell( 2, 4).Range.Text.rstrip()[:-2] zongsu = shuomingfile.Tables[i].Cell( 4, 2).Range.Text.rstrip()[:-2] zhui_temp = shuomingfile.Tables[i].Cell( 3, 2).Range.Text.rstrip()[:-2] else: self.sin_out.emit("未找到合适的填写数据,退出处理") print("未找到合适的填写数据") self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return shuomingfile.Tables[i].Rows.First.Select() # 获取测试项章节号 #############################目前模板不用获取用例章节号暂时省去 # zhangjiehao = self.w.Selection.Bookmarks("\headinglevel"). \ # Range.Paragraphs(1).Range.ListFormat.ListString # 获取测试项章节名 ############################################################## zhangjieming = self.w.Selection.Bookmarks("\headinglevel"). \ Range.Paragraphs(1).Range.Text.rstrip('\r') yongli_dict['yongli_ming'] = yongliming yongli_dict['yongli_biaoshi'] = biaoshi data2['yongli_ming'] = yongliming data2['yongli_biaoshi'] = biaoshi data2['yongli_zongsu'] = zongsu data2_list.append(data2) print("当前yongli_dict为:", yongli_dict) # 获取大纲的章节号和用例名,而且data按自己的来 ## 按python行进行分割为列表 zhui_list = zhui_temp.split("\r") if len(zhui_list) == 3: if zhui_list[1].find("需求") != -1: #使用re模块正则表达式 match_string = re.search( "\d(.\d+)+", zhui_list[1]).group() match_ming = zhui_list[1].split( match_string)[-1] #使用re.sub模块替换为空 rules = "[)()(] " match_ming = re.sub(rules, '', match_ming) if zhui_list[2]: rules = ":" dg_biaoshi_temp = re.sub( rules, ':', zhui_list[2]) dg_biaoshi = dg_biaoshi_temp.split(":")[-1] #判断是否是新的测试项,如果是新的索引index加1,创建新dict进入 if zhangjieming != csx_name: data_list.append(data) data_index = data['index'] + 1 data = { 'dg_zhangjie': '', 'mingcheng': '', 'biaoshi': '', 'yongli': [], 'index': data_index } data['dg_zhangjie'] = match_string data['mingcheng'] = match_ming data['biaoshi'] = dg_biaoshi data['yongli'].append(yongli_dict) csx_name = zhangjieming self.sin_out.emit("已处理第{}个测试项...".format( data['index'])) else: data['yongli'].append(yongli_dict) except: self.sin_out.emit( f'$$$$$$$$$$$$第{str(i+1)}个表格,获取单元格内容不存在$$$$$$$$$$$$') pass # 最后关闭文档 try: self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) except: QMessageBox.warning(self.parent, "关闭文档失败", "关闭文档失败!") return try: tpl_path = Path.cwd( ) / "need" / "document_templates" / "说明追踪模板.docx" self.sin_out.emit('导入模板文件路径为:' + str(tpl_path)) tpl = DocxTemplate(tpl_path) # 模板导入成功 except: QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确") return # 开始渲染模板文件 try: context = { "tables": data_list, "tables2": data2_list, } tpl.render(context) tpl.save("说明追踪文档.docx") self.sin_out.emit('stopsuccess') except: self.sin_out.emit('stoperror') return ################################################################################## #根据说明生成测试记录线程 ################################################################################## class create_jilu(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): #用来储存章节号转换 zhuan_dict = {'DC':'文档审查','SU':'功能测试','CR':'代码审查','SA':'静态分析','AC':'性能测试',\ 'IO':'接口测试','SE':'安全性测试','BT':'边界测试','RE':'恢复性测试','ST':'强度测试',\ 'AT':'余量测试','GUI':'人机交互界面测试','DP':'数据处理测试','JR':'兼容性测试',\ 'LG':'逻辑测试','AZ':'安装性测试','TT':'时序测试','PA':'功耗分析'} self.sin_out.emit("进入根据说明转换记录线程......") self.sin_out.emit("开始转换......") #如果没有选择文件则退出 if not self.parent.open_file_name: self.sin_out.emit('nofile') self.parent.tabWidget.setEnabled(True) return pythoncom.CoInitialize() self.sin_out.emit('打开说明文档...') self.w = DispatchEx('Word.Application') self.w.DisplayAlerts = 0 try: shuomingfile = self.w.Documents.Open(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:选择的文档') self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return self.sin_out.emit('复制测试记录文档模板到本程序所在目录...') curpath = Path.cwd() / 'need' shuoming_path_tmp = curpath / 'document_templates' / '说明生成记录模板.docx' if shuoming_path_tmp.is_file(): self.sin_out.emit('已检测到有记录模板文件...') else: self.sin_out.emit('open failed:选择的文档') return #创建一个字典来储存单个用例 data_list = [] #获取表格数量 try: csx_tb_count = shuomingfile.Tables.Count self.sin_out.emit('total:' + str(csx_tb_count)) except: self.sin_out.emit('不存在表格,请检查文档!') QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格') try: shuomingfile.Close() except: pass self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return #用来储存章节号中的DC、SU等标识,用于章节号判断 is_type_su = "" #储存章节号标志 is_fire_su = "" for i in range(csx_tb_count): self.sin_out.emit(str(i)) self.sin_out.emit("正在处理第{}个表格".format(i + 1)) try: if shuomingfile.Tables[i].Rows.Count > 2: if shuomingfile.Tables[i].Cell( 2, 1).Range.Text.find('测试用例名称') != -1: #一个用例不变内容获取 try: shuomingfile.Tables[i].Rows.First.Select() #获取章节名,用于判断 zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\ Range.Paragraphs(1).Range.Text.rstrip('\r') #获取表格基本信息 mingcheng = shuomingfile.Tables[i].Cell( 2, 2).Range.Text[:-2] biaoshi = shuomingfile.Tables[i].Cell( 2, 4).Range.Text[:-2] self.sin_out.emit(f"正在处理{biaoshi}用例{mingcheng}") zhuizong = shuomingfile.Tables[i].Cell( 3, 2).Range.Text[:-2] zongsu = shuomingfile.Tables[i].Cell( 4, 2).Range.Text[:-2] chushihua = shuomingfile.Tables[i].Cell( 5, 2).Range.Text[:-2] qianti = shuomingfile.Tables[i].Cell( 6, 2).Range.Text[:-2] #缓存一个data数据 data = {'mingcheng':'','biaoshi':'','zhuizong':'','is_first':'0',\ 'zongsu':'','chushihua':'','qianti':'','zuhe':[],'is_begin':'0',\ 'csx_type':'','csx_name':''} #获取步骤和预期 step_count = shuomingfile.Tables[i].Rows.Count - 11 for j in range(step_count): buzhou_dict = { 'buzhou': "", 'yuqi': "", 'xuhao': '' } buzhou_dict['buzhou'] = shuomingfile.Tables[ i].Cell(j + 9, 2).Range.Text[:-2] buzhou_dict['yuqi'] = shuomingfile.Tables[ i].Cell(j + 9, 3).Range.Text[:-2] buzhou_dict['xuhao'] = str(j + 1) data['zuhe'].append(buzhou_dict) #开始判断当前是否为测试项的第一个,如果是第一个则is_first改为1 if is_fire_su != zhangjieming: is_fire_su = zhangjieming data['is_first'] = '1' #判断测试类型,这里从标识里面获取 biaoshi_list = biaoshi.split("_") print('当前取的类型列表分割:', biaoshi_list) if len(biaoshi_list) >= 4: biaoshi_tmp = biaoshi_list[-3] else: biaoshi_tmp = biaoshi_list[1] if biaoshi_tmp != is_type_su: is_type_su = biaoshi_tmp data['is_begin'] = '1' if zhuan_dict[biaoshi_tmp] == '文档审查' or zhuan_dict[biaoshi_tmp] == '代码审查' or \ zhuan_dict[biaoshi_tmp] == '静态分析': data['is_first'] = '0' #data补全 data['mingcheng'] = mingcheng data['biaoshi'] = biaoshi data['zhuizong'] = zhuizong.replace('\r', '\n') data['zongsu'] = zongsu data['chushihua'] = chushihua data['qianti'] = qianti data['csx_type'] = zhuan_dict[biaoshi_tmp] data['csx_name'] = zhangjieming data_list.append(data) self.sin_out.emit("处理完毕{}用例".format(biaoshi)) except: self.sin_out.emit(f'错误!第{i+1}个表格处理失败!') except: self.sin_out.emit(f'错误!第{i+1}个表格处理失败!') #关闭大纲文档(因为以及提取完毕) try: shuomingfile.Close() self.w.Quit() pythoncom.CoUninitialize() except: self.sin_out.emit('function fail') self.w.Quit() pythoncom.CoUninitialize() return #打开模板文件进行渲染,然后就是用docxtpl生成用例 try: tpl_path = Path.cwd( ) / "need" / "document_templates" / "说明生成记录模板.docx" self.sin_out.emit('导入模板文件路径为:' + str(tpl_path)) tpl = DocxTemplate(tpl_path) #模板导入成功 except: QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确") return #开始渲染模板文件-有2层循环 try: context = { "tables": data_list, "cs_renyuan": self.parent.lineEdit_4.text(), "jc_renyuan": self.parent.lineEdit_5.text(), "shijian": self.parent.lineEdit_6.text(), } tpl.render(context) tpl.save("生成的测试记录文档.docx") self.sin_out.emit('stopsuccess') except: self.sin_out.emit('stoperror') return ################################################################################## # 根据测试记录反向生成说明 ################################################################################## class create_shuomingfanxiang(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): # 用来储存测试项DC等转换 zhuan_dict = {'DC':'文档审查','SU':'功能测试','CR':'代码审查','SA':'静态分析','AC':'性能测试',\ 'IO':'接口测试','SE':'安全性测试','BT':'边界测试','RE':'恢复性测试','ST':'强度测试',\ 'AT':'余量测试','GUI':'人机交互界面测试','DP':'数据处理测试','JR':'兼容性测试',\ 'LG':'逻辑测试','AZ':'安装性测试','TT':'时序测试','PA':'功耗分析'} self.sin_out.emit("进入测试记录转说明......") self.sin_out.emit("开始转换......") # 如果没有选择文件路径则退出 if not self.parent.open_file_name: self.sin_out.emit('nofile') self.parent.tabWidget.setEnabled(True) return pythoncom.CoInitialize() self.sin_out.emit('打开测试记录文件...') self.w = DispatchEx('Word.Application') #self.w.visible=True self.w.DisplayAlerts = 0 try: jilufile = self.w.Documents.Open(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:选择的文档') self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return self.sin_out.emit('复制测试说明文档模板到本程序所在目录...') curpath = Path.cwd() / 'need' shuoming_path_tmp = curpath / 'document_templates' / '反向测试说明模板.docx' print(shuoming_path_tmp) if shuoming_path_tmp.is_file(): self.sin_out.emit('已检测到有说明模板文件...') else: self.sin_out.emit('open failed:选择的文档') return #创建一个字典来储存单个用例 data_list = [] #获取表格数量 try: csx_tb_count = jilufile.Tables.Count self.sin_out.emit('total:' + str(csx_tb_count)) except: self.sin_out.emit('不存在表格!') QMessageBox.warning(self.parent, '出错了', '测试说明文档格式错误或者没有正确表格') try: jilufile.Close() except: pass self.w.Quit() pythoncom.CoUninitialize() self.parent.tabWidget.setEnabled(True) return #初始化表格外全局变量 is_fire_su = '' is_type_su = '' for i in range(csx_tb_count): self.sin_out.emit(str(i)) self.sin_out.emit(f"正在处理第{str(i+1)}个表格") if jilufile.Tables[i].Rows.Count > 2: if jilufile.Tables[i].Cell(2, 1).Range.Text.find('测试用例名称') != -1: #将表格中信息全部先拿出来 try: jilufile.Tables[i].Rows.First.Select() zhangjieming = self.w.Selection.Bookmarks("\headinglevel").\ Range.Paragraphs(1).Range.Text.rstrip('\r') zhangjiehao = self.w.Selection.Bookmarks("\headinglevel").\ Range.Paragraphs(1).Range.ListFormat.ListString mingcheng = jilufile.Tables[i].Cell(2, 2).Range.Text[:-2] biaoshi = jilufile.Tables[i].Cell(2, 4).Range.Text[:-2] self.sin_out.emit(f"正在处理{biaoshi}-用例{mingcheng}") zhuizong = jilufile.Tables[i].Cell(3, 2).Range.Text[:-2] zongsu = jilufile.Tables[i].Cell(4, 2).Range.Text[:-2] chushi = jilufile.Tables[i].Cell(5, 2).Range.Text[:-2] qianti = jilufile.Tables[i].Cell(6, 2).Range.Text[:-2] #缓存一个data数据 data = {'mingcheng':'','biaoshi':'','zhuizong':'','is_first':'0',\ 'zongsu':'','chushi':'','qianti':'','zuhe':[],'is_begin':'0',\ 'csx_type':'','csx_mingcheng':'','renyuan':''} #获取步骤和预期 step_count = jilufile.Tables[i].Rows.Count - 12 #获取人员信息 data['renyuan'] = jilufile.Tables[i].Cell( 10 + step_count, 2).Range.Text[:-2] for j in range(step_count): buzhou_dict = { 'buzhou': "", 'yuqi': "", 'xuhao': '' } buzhou_dict['buzhou'] = jilufile.Tables[i].Cell( j + 9, 2).Range.Text[:-2] buzhou_dict['yuqi'] = jilufile.Tables[i].Cell( j + 9, 3).Range.Text[:-2] buzhou_dict['xuhao'] = str(j + 1) data['zuhe'].append(buzhou_dict) # 开始判断当前是否为测试项的第一个,如果是第一个则is_first改为1 if is_fire_su != zhangjieming: is_fire_su = zhangjieming data['is_first'] = '1' # 判断测试类型,这里从标识里面获取 biaoshi_list = biaoshi.split("_") print('当前取的类型列表分割:', biaoshi_list) if len(biaoshi_list) >= 4: biaoshi_tmp = biaoshi_list[-4] else: biaoshi_tmp = biaoshi_list[1] if biaoshi_tmp != is_type_su: is_type_su = biaoshi_tmp data['is_begin'] = '1' if zhuan_dict[biaoshi_tmp] == '文档审查' or zhuan_dict[biaoshi_tmp] == '代码审查' or \ zhuan_dict[biaoshi_tmp] == '静态分析': data['is_first'] = '0' #data补全 data['mingcheng'] = mingcheng data['biaoshi'] = biaoshi data['zhuizong'] = zhuizong.replace('\r', '\n') data['zongsu'] = zongsu data['chushi'] = chushi data['qianti'] = qianti data['csx_type'] = zhuan_dict[biaoshi_tmp] data['csx_mingcheng'] = zhangjieming data_list.append(data) self.sin_out.emit("处理完毕{}用例".format(biaoshi)) except: self.sin_out.emit("第{}个表格处理失败,请检查".format(str(i + 1))) pass else: self.sin_out.emit( "该表格生成错误,请检查是否存在用例序号,每个用例必须有序号且必须包含【记录】两个字...") else: self.sin_out.emit("该表格生成错误,请检查表格是否存在并大于2行...") #关闭大纲文档(因为以及提取完毕) try: jilufile.Close() self.w.Quit() pythoncom.CoUninitialize() except: self.sin_out.emit('function fail') self.w.Quit() pythoncom.CoUninitialize() return #打开模板文件进行渲染,然后就是用docxtpl生成用例 try: tpl_path = Path.cwd( ) / "need" / "document_templates" / "反向测试说明模板.docx" self.sin_out.emit('导入模板文件路径为:' + str(tpl_path)) tpl = DocxTemplate(tpl_path) #模板导入成功 except: QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确") return #开始渲染模板文件-有2层循环 try: context = { "tables": data_list, } tpl.render(context) tpl.save("反向生成的说明文档.docx") self.sin_out.emit('stopsuccess') except: self.sin_out.emit('stoperror') return ################################################################################## #自动填充单元格线程 ################################################################################## class create_zidong(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): self.sin_out.emit('开始...') if self.parent.open_file_name == '': self.sin_out.emit('请点击“选择文档”按钮选择要填充的文档') self.parent.tabWidget.setEnabled(True) QMessageBox.warning(self.parent, '出错了!', '请选择要填充的文档!') return try: t_s_file = docx.Document(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:选择的文档') self.parent.tabWidget.setEnabled(True) QMessageBox.warning(self.parent, '出错了!', '打开选择的文档失败,请确认文档类型为docx,且未被打开!') return if self.parent.lineEdit_9.text() == '': self.sin_out.emit('单元格左侧不能为空!!!!') self.parent.tabWidget.setEnabled(True) QMessageBox.warning(self.parent, '出错了!', '单元格标题不能为空!') return if self.parent.lineEdit_10.text() == '': self.sin_out.emit('确定填充内容为空吗?填充内容为空相当于清空操作。可直接点击清空按钮!!') self.parent.tabWidget.setEnabled(True) QMessageBox.warning(self.parent, '警告!', '确定填充内容为空吗?填充内容为空相当于清空操作。可点击清空按钮!!') return tmp_fill = self.parent.lineEdit_11.text() if tmp_fill == '': tmp_fill = str(len(t_s_file.tables)) if (tmp_fill.strip().isdigit()) and (int(tmp_fill.strip()) < len( t_s_file.tables)): tmp_ran = int(tmp_fill) else: tmp_ran = len(t_s_file.tables) tmp_fillnum = 0 k = 0 self.sin_out.emit('total:' + str(tmp_ran)) self.parent.progressBar.setRange(0, tmp_ran - 1) for ft1 in t_s_file.tables: k += 1 self.sin_out.emit(str(k)) self.parent.progressBar.setValue(k) tmp_row = 0 for r in ft1.rows: tmpflag = 0 tmp_column = 0 for cell in r.cells: if cell.text.strip() == self.parent.lineEdit_9.text(): while ft1.cell(tmp_row, tmp_column).text.strip( ) == self.parent.lineEdit_9.text(): tmp_column += 1 #这里如果需要替换还是不替换 if ft1.cell(tmp_row, tmp_column).text == '': ft1.cell(tmp_row, tmp_column ).text = self.parent.lineEdit_10.text() tmp_fillnum += 1 else: pass tmpflag = 1 break else: tmp_column += 1 if tmpflag == 1: break tmp_row += 1 if tmp_fillnum >= int(tmp_fill): break try: t_s_file.save(self.parent.open_file_name[0]) self.sin_out.emit('function success') self.parent.tabWidget.setEnabled(True) return except: self.parent.tabWidget.setEnabled(True) self.sin_out.emit('function fail') QMessageBox.information(self.parent, '', '填充完成!') return ################################################################################## #清空单元格线程 ################################################################################## class clear_cell(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): self.sin_out.emit('开始...') if self.parent.open_file_name == '': self.sin_out.emit('请点击“选择文档”按钮选择要填充的文档') self.parent.tabWidget.setEnabled(True) QMessageBox.warning(self.parent, '出错了!', '请选择要填充的文档!') return try: t_s_file = docx.Document(self.parent.open_file_name[0]) except: self.sin_out.emit('open failed:要填充的文档') QMessageBox.warning(self.parent, '出错了!', '打开选择的文档失败,请确认文档类型为docx,且未被打开!') self.parent.tabWidget.setEnabled(True) return if self.parent.lineEdit_9.text() == '': self.parent.tabWidget.setEnabled(True) self.sin_out.emit('单元格标题不能为空!') QMessageBox.warning(self.parent, '出错了!', '单元格标题不能为空!') return tmp_tblcnt = len(t_s_file.tables) k = 0 self.sin_out.emit('total:' + str(tmp_tblcnt)) for ft1 in t_s_file.tables: k += 1 self.sin_out.emit(str(k)) tmp_row = 0 for r in ft1.rows: tmpflag = 0 tmp_column = 0 for cell in r.cells: if cell.text.strip() == self.parent.lineEdit_9.text(): while ft1.cell(tmp_row, tmp_column).text.strip( ) == self.parent.lineEdit_9.text(): tmp_column += 1 ft1.cell(tmp_row, tmp_column).text = '' tmpflag = 1 break else: tmp_column += 1 if tmpflag == 1: break tmp_row += 1 try: t_s_file.save(self.parent.open_file_name[0]) self.sin_out.emit('function success') self.parent.tabWidget.setEnabled(True) return except: self.parent.tabWidget.setEnabled(True) self.sin_out.emit('function fail') QMessageBox.information(self.parent, '', '清空单元格成功!') return ################################################################################## #提取表格内容线程 ################################################################################## class get_content(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent #获取文档中表格内容函数 def run(self): curpath = Path.cwd() content_tmp = curpath / 'need' / 'document_templates' / 'get_content.docx' shutil.copy(content_tmp, curpath) content_tmp_path = curpath / 'get_content.docx' print(content_tmp_path) try: #c_file = self.w.Documents.Add() c_file = docx.Document(content_tmp_path) except: self.sin_out.emit('open failed:文档模板') self.parent.tabWidget.setEnabled(True) return try: s_file = docx.Document(self.parent.open_file_name[0]) s_tbls = s_file.tables except: self.sin_out.emit('open failed:选择的文档') c_file.save(content_tmp_path) self.parent.tabWidget.setEnabled(True) return #原来是5,6,7 if self.parent.lineEdit_12.text( ) == '' and self.parent.lineEdit_13.text( ) == '' and self.parent.lineEdit_14.text() == '': self.sin_out.emit( 'warning:请至少填写一个要提取的内容的标题,\n标题为要提取的单元格的前一单元格中的内容!') c_file.save(content_tmp_path) s_file.save(self.parent.open_file_name[0]) self.parent.tabWidget.setEnabled(True) return line_list = [ self.parent.lineEdit_12.text(), self.parent.lineEdit_13.text(), self.parent.lineEdit_14.text() ] self.sin_out.emit('开始提取...') rownum = 0 self.sin_out.emit('total:' + str(len(s_tbls))) for stb in s_tbls: c_file.tables[0].add_row() rownum += 1 self.sin_out.emit(str(rownum)) row = 0 for r1 in stb.rows: col = 0 for ce in r1.cells: if line_list[0] != '' and ce.text == line_list[0]: while stb.cell(row, col).text == line_list[0]: col += 1 c_file.tables[0].cell(rownum, 0).text = stb.cell(row, col).text break col += 1 col = 0 for ce in r1.cells: if line_list[1] != '' and ce.text == line_list[1]: while stb.cell(row, col).text == line_list[1]: col += 1 c_file.tables[0].cell(rownum, 1).text = stb.cell(row, col).text break col += 1 col = 0 for ce in r1.cells: if line_list[2] != '' and ce.text == line_list[2]: while stb.cell(row, col).text == line_list[2]: col += 1 c_file.tables[0].cell(rownum, 2).text = stb.cell(row, col).text break col += 1 row += 1 try: c_file.save(content_tmp_path) s_file.save(self.parent.open_file_name[0]) self.sin_out.emit('function success') self.sin_out.emit('生成文件名为(get_content.docx),在根目录下查看') self.parent.tabWidget.setEnabled(True) return except: self.sin_out.emit('function fail') self.parent.tabWidget.setEnabled(True) return ################################################################################## #测评报告追溯表 ################################################################################## class create_baogao_zhuisu(QtCore.QThread): sin_out = pyqtSignal(str) def __init__(self, parent): super().__init__() self.parent = parent def run(self): self.sin_out.emit("进入报告追溯线程......") self.sin_out.emit("开始填写报告追溯表......") # 如果没有选择文件 if not self.parent.open_file_name: self.sin_out.emit('nofile') self.parent.tabWidget.setEnabled(True) return self.sin_out.emit('打开测试记录文档...') # 打开word应用 try: doc_path = self.parent.open_file_name[0] doc = Document(doc_path) except: self.sin_out.emit('open failed:选择的文档') self.parent.tabWidget.setEnabled(True) return self.sin_out.emit('已正确打开说明文档...') curpath = Path.cwd() / 'need' zhuisu_path_tmp = curpath / 'document_templates' / '报告追踪模板.docx' if zhuisu_path_tmp.is_file(): self.sin_out.emit('已检测到有报告追溯模板文件...') else: self.sin_out.emit('open failed:选择的文档') return # 创建个列表放数据 data_list = [] # 由于docx的是列表,所以直接len函数统计count count = len(doc.tables) self.sin_out.emit('total:' + str(count)) k = 0 for tb in doc.tables: k += 1 self.sin_out.emit('total:' + str(k)) #注意docx处理方式不一样从0开始,并且要算总行数 try: if tb.cell(1, 1).text.find('测试用例名称') != -1: data = { 'yongli_ming': '', 'yongli_biaoshi': '', 'yongli_qingkuang': '', 'beizhu': '' } data['yongli_ming'] = tb.cell(1, 4).text data['yongli_biaoshi'] = tb.cell(1, 8).text wenti = tb.rows[-2].cells[2] print('提取出来的信息:', wenti.text) if wenti.text == '/' or wenti.text == '': data['yongli_qingkuang'] = '通过' data['beizhu'] = '/' else: data['yongli_qingkuang'] = '不通过' data['beizhu'] = wenti.text self.sin_out.emit(f'处理完毕({tb.cell(1,8).text})用例..') data_list.append(data) else: self.sin_out.emit(f'当前表格({tb.cell(1,8).text})用例无法识别请检查') except: self.sin_out.emit(f'处理第{k}个表格失败,请检查该表格...') pass try: tpl_path = Path.cwd( ) / "need" / "document_templates" / '报告追踪模板.docx' self.sin_out.emit('导入模板文件路径为:' + str(tpl_path)) tpl = DocxTemplate(tpl_path) # 模板导入成功 except: QMessageBox.warning(self.parent, "出错了", "导入模板出错请检查模板文件是否存在或名字不正确") return # 开始渲染模板文件 print(data_list) try: context = { "tables": data_list, } tpl.render(context) tpl.save("说明追踪文档.docx") self.sin_out.emit('stopsuccess') except: self.sin_out.emit('stoperror') return ################################################################################## ## ##################################################################################