首先上点废话:
正交表例如L9(3^4),表1-1, 它表示需作9次实验,最多可观察4个因素,每个因素均为3水平。一个正交表中也可以各列的水平数不相等,我们称它为混合型正交表,如L8(4^1×2^4),表2-1 ,此表的5列中,有1列为4水平,4列为2水平。根据正交表的数据结构看出,正交表是一个n行c列的表,其中第j列由数码1,2,… Sj 组成,这些数码均各出现n/Sj 次,例如表1-1中,第二列的数码个数为3,S=3 ,即由1、2、3组成,各数码均出现3次。
大概意思就是:
现在有一软件,他可以在不同的环境下运行,而这些环境因子可以让程序正常运行或是崩溃,现在需要做出测试用例,能够让这些因素都能够被测完,如果是正常的正交,那么需要花费大量的用例才能够测完。现在,经过大量的实验得到了一个既能测完所有因素,又能尽可能地减少测试次数的正交表。
上点效果图:
生成的xlsx文件:
接下来上文件结构:
开始界面部分:
自个儿在QtDesigner拖拖拽拽,然后保存用pyuic来编译.ui文件成为.py文件,这时候生成的.py文件可以作为一个资源看待,还要另外创建一个uirun.py文件来让界面出来。
下面是uirun.py代码:
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QInputDialog, qApp
from MainWindows import *
from PyQt5.QtCore import Qt
import re
from run import CreateXlsx
import pandas
import numpy
import getfilename
import sys
class MyMainWindow(QMainWindow, Ui_MainWindow):
text = getfilename.get_data()
head = re.findall(r'\d+\^[\d\D]*?=\d+', text)
def __init__(self):
super(MyMainWindow, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(qApp.quit)
self.btn_input.clicked.connect(self.btn_input_clicked)
self.btn_help.clicked.connect(self.btn_help_clicked)
self.combox_init()
def combox_init(self):
self.comboBox.addItem('')
self.comboBox.addItems(self.head)
self.comboBox.activated.connect(self.combox_change)
def combox_change(self):
if self.comboBox.currentIndex() == 0:
return
ldlist = re.findall(r'\d*\^\d*', self.comboBox.currentText())
head = self.comboBox.currentText()
lddict = {}
mydict = {}
#开始输入因子名
for i in ldlist:
tlist = i.split('^')
lddict.update({int(tlist[0]): int(tlist[1])})
namelist = []
for key in lddict:
a = []
while len(a) != lddict[key]:
text, ok = QInputDialog.getMultiLineText(self, "输入", "请输入%d水平%d因子的%d个因子名" %
(key, lddict[key], lddict[key]))
if ok:
a = text.split('\n')
for i in range(0, a.count('')): # 删除空字符
a.remove('')
self.comboBox.setEnabled(False)
else:
self.comboBox.setEnabled(True)
return
if len(a) != lddict[key]:
QMessageBox.information(self, '提示', '输入有误,请重新输入')
namelist.extend(a)
#结束输入因子名
#开始输入水平变量名
count = 0
for key in lddict:
i = 0
while i != lddict[key]:
text, ok = QInputDialog.getMultiLineText(self, "输入", "请输入%d水平%s因子的%d个水平变量" %
(key, namelist[count], key))
if ok:
a = text.split('\n')
for j in range(0, a.count('')): # 删除空字符
a.remove('')
else:
self.comboBox.setEnabled(True)
return
if len(a) == key:
for k in range(0, len(a)):
item = {str(count) + ',' + str(k): a[k]}
mydict.update(item)
count = count + 1
else:
QMessageBox.information(self, '提示', '输入有误,请重新输入')
continue
i = i + 1
#结束输入水平变量名
#创建xlsx文档
xlsx = CreateXlsx(head, namelist, mydict, count)
filename = xlsx.create()
#结束创建
self.write_table(filename)
def btn_input_clicked(self):
text, ok = QInputDialog.getMultiLineText(self, '输入因子和水平', '请输入因子和变量')
if ok:
#处理输入
tlist = text.split('\n')
tlist = self.remove_empty(tlist)
for i in range(0, len(tlist)):
tlist[i] = tlist[i].replace(':', ':')
if ''.join(tlist).count(':') == 0:
QMessageBox.information(self, '提示', '输入不符合规范!')
return
tlist = self.get_pure_list(tlist)
tlist.sort(key=self.get_num_item) #排序,使输入规范化
#处理输入
namelist = [] #第二参数,用于存储因子名
level = [] #用于记录水平变量
for i in tlist:
a = i.split(':')
namelist.append(a[0])
level.append(a[1])
count = len(namelist) #第四参数,总因子数
levelnum = [] #用于记录水平数
for i in level:
t = i.split(' ')
t = self.remove_empty(t)
levelnum.append(len(t))
inhead = set() #用于解析出数据头
for i in levelnum:
inhead.add(str(i) + '^' + str(levelnum.count(i)))
else:
return
inhead = list(inhead)
inhead.sort(key=lambda x: int(x.split('^')[0]), reverse=False)
tmtext = "\n".join(self.head)
pattern = " ".join(inhead)
t = re.findall(pattern.replace('^', r'\^') + r' +n=\d+', tmtext)
if len(t) == 0:
QMessageBox.information(self, '提示', '抱歉!正交表中不存在对应方案!')
return
head = t[0] #第一个参数
mydict= {} #第三参数
for i in range(0, count):
for j in range(0, len(level[i].split(' '))):
mydict.update({str(i) + ',' + str(j): level[i].split(' ')[j]})
xlsx = CreateXlsx(head, namelist, mydict, count)
filename = xlsx.create()
self.write_table(filename)
def remove_empty(self, olist):
for i in range(0, olist.count('')):
olist.remove('')
return olist
def get_pure_list(self, list): #获得处理后的列表,处理多余空格
for i in range(0, len(list)):
t = list[i].split(':')
list[i] = t[0] + ':' + ' '.join(self.remove_empty(t[1].split(' ')))
return list
def get_num_item(self, item): #获得水平数,用于排序
t = item.split(':')
return len(t[1].split(' '))
def write_table(self, filename): #使xlsx文件显示在界面上
# 读取文件
input_xlsx = pandas.read_excel(filename)
input_xlsx_rows = input_xlsx.shape[0]
input_xlsx_cols = input_xlsx.shape[1]
input_xlsx_header = input_xlsx.columns.values.tolist()
# 设置行列表
self.tableWidget.setColumnCount(input_xlsx_cols)
self.tableWidget.setRowCount(input_xlsx_rows)
self.tableWidget.setHorizontalHeaderLabels(input_xlsx_header)
# 设置行列表
# 开始写单元格
for i in range(input_xlsx_rows):
input_xlsx_rows_values = input_xlsx.iloc[[i]]
input_xlsx_rows_values_array = numpy.array(input_xlsx_rows_values)
input_xlsx_rows_values_list = input_xlsx_rows_values_array.tolist()[0]
for j in range(input_xlsx_cols):
input_xlsx_items_list = input_xlsx_rows_values_list[j]
# 开始写到界面上
input_xlsx_items = str(input_xlsx_items_list)
newItem = QtWidgets.QTableWidgetItem(input_xlsx_items)
newItem.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.tableWidget.setItem(i, j, newItem)
QMessageBox.information(self, '提示', '已生成xlsx文件!')
self.comboBox.setEnabled(True)
def btn_help_clicked(self):
with open(getfilename.get_path() + '/help', 'r') as f:
text = f.read()
QMessageBox.about(self, '帮助', text)
if __name__ == '__main__':
app = QApplication(sys.argv)
myWin = MyMainWindow()
myWin.show()
sys.exit(app.exec_())
下面是代码运行部分:
run.py
from openpyxl import Workbook
import re
import getfilename
import time
class CreateXlsx:
head = ''
namelist = []
mydict = {}
count = 0
def __init__(self, head, namelist, mydict, count):
self.head = head
self.namelist = namelist
self.mydict = mydict
self.count = count
def create(self):
text = getfilename.get_data()
# 开始获取文件中的正交表
pattern = self.head.replace('^', r'\^') + r'[\d\D]+?\n\n'
temp = re.findall(pattern, text)[0]
n = int(re.findall(r'n=\d+', temp)[0].split('=')[-1])
content = re.findall(r'0[\d\D]*\n\n| 0[\d\D]*\n\n', temp)[0].split('\n') # 正交表具体内容
t = re.findall(r'\d{2}\^\d+', self.head)
dbn = 0 # 拥有两位数水平数的因子数量
for i in t:
if int(i.split('^')[0]) > 10: #大于10即有两位数
dbn += int(i.split('^')[-1])
for i in range(content.count('')): #去除空字符
content.remove('')
insidelist = []
dbstart_index = self.count - dbn
print(dbstart_index)
temp = ''
for y in range(n):
for x in range(self.count + dbn):
if x >= dbstart_index:
if ((x - dbstart_index) % 2) == 0:
temp = content[y][x]
else:
temp += content[y][x]
insidelist.append(temp.replace(' ', ''))
else:
insidelist.append(content[y][x])
print(insidelist)
wb = Workbook()
ws = wb.active
for x in range(0, self.count):
ws.cell(1, x + 1, self.namelist[x])
for y in range(0, n):
for x in range(0, self.count):
ws.cell(y + 2, x + 1, self.mydict[str(x) + ',' + insidelist[x + self.count * y]])
unix_time = str(time.time())
filename = unix_time + '.xlsx'
wb.save(filename)
return filename
getfilename.py
至于为什么要搞这玩意出来,那是因为在打包过后的exe需要的data数据不在.exe所在的文件路径下,而是在系统盘的临时文件夹中,可以通过判断来找出data在哪。
import os
import sys
def get_data():
if os.path.isfile(sys.path[0]):
filename = os.path.join(os.path.dirname(sys.path[0]), 'data')
else:
filename = os.path.join(sys.path[0], 'data')
with open(filename, 'r') as f:
text = f.read()
return text
写完这小工具还用到了openxl写文件,pandas读xlsx文件,制作Ui时在MainWindow下进行layout可以实现窗口与控件一起缩放(以前压根不懂)
关于打包时的spec:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['uirun.py'],
pathex=['F:\\Testtools'],
binaries=[],
datas=[('data','.'),('help','.')],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='uirun',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False , icon='tools.ico')