编写测试框架实现测试报告自动生成与自动邮件发送
前台页面功能:
1.以表格形式生成测试报告,csv文件中可以设定用例执行优先级与是否执行
2.以表格形式生成测试报告与生成bug报告
3.以表格形式生成测试报告、bug报告与哪个研发的功能有bug就自动给对应研发发邮件
4.已html格式生成测试报告,只适用于unittest框架
1、2、3用联动效果选择生成
测试用例信息csv文件
testcase_ind_a.py
from atstudy_testframe.atstudy_test_frame2 import report_testframe,bug_testframe import csv class testcase_ind_a(): def __init__(self): self.sucnum=0 self.errnum=0 print("testcase_int_a测试初始化") def test_case1(self,t1): print("testcase_int_a测试用例方法1") if t1>0: self.sucnum = self.sucnum + 1 return("测试成功") else: self.errnum = self.errnum + 1 return ("测试失败") def test_case2(self,t2): #print("testcase_ind_a测试用例方法2") if t2==9: self.sucnum=self.sucnum+1 return ("测试成功") else: self.errnum=self.errnum+1 return ("测试失败") if __name__ == '__main__': resultdic={} bugdic={} obj=testcase_ind_a() r1=obj.test_case1(-1) if r1=="测试失败": # bugObj=bug_testframe() # bugObj.addbugresult("test_case1",r1) bugdic["test_case1"]=r1 resultdic["test_case1"]=r1 r2=obj.test_case2(9) if r2=="测试失败": # bugObj=bug_testframe() # bugObj.addbugresult("test_case2",r2) bugdic["test_case2"] = r2 resultdic["test_case2"]=r2 #obj.test_case1() # obj.test_case2() # print(resultdic) print("存放bug的数据字典",bugdic) print("存放结果的字典",resultdic) repobj=report_testframe() repobj.addtestreport(str(resultdic),str(obj.sucnum),str(obj.errnum)) print(obj.errnum) if obj.errnum>0: bugObj=bug_testframe() bugObj.addbugresult(bugdic)
testcase_ind_a2.py
# coding=gbk from atstudy_testframe.atstudy_test_frame2 import report_testframe,bug_testframe import csv class testcase_ind_a2(): def __init__(self): self.sucnum=0 self.errnum=0 print("testcase_int_a2测试初始化") def test_case3(self,t1): print("testcase_int_a2测试用例方法1") if t1>0: self.sucnum = self.sucnum + 1 return("测试成功") else: self.errnum = self.errnum + 1 return ("测试失败") def test_case4(self,t2): #print("testcase_ind_a测试用例方法2") if t2==9: self.sucnum=self.sucnum+1 return ("测试成功") else: self.errnum=self.errnum+1 return ("测试失败") if __name__ == '__main__': resultdic={} bugdic={} obj=testcase_ind_a2() r1=obj.test_case3(-1) if r1=="测试失败": # bugObj=bug_testframe() # bugObj.addbugresult("test_case1",r1) bugdic["test_case3"]=r1 resultdic["test_case3"]=r1 r2=obj.test_case4(8) if r2=="测试失败": # bugObj=bug_testframe() # bugObj.addbugresult("test_case2",r2) bugdic["test_case4"] = r2 resultdic["test_case4"]=r2 #obj.test_case1() # obj.test_case2()
testcase_ind_a3.py
# coding=gbk from atstudy_testframe.atstudy_test_frame2 import report_testframe,bug_testframe import csv class testcase_ind_a3(): def __init__(self): self.sucnum=0 self.errnum=0 print("testcase_int_a4测试初始化") def test_case5(self,t1): print("testcase_int_a4测试用例方法1") if t1>0: self.sucnum = self.sucnum + 1 return("测试成功") else: self.errnum = self.errnum + 1 return ("测试失败") def test_case6(self,t2): #print("testcase_ind_a测试用例方法2") if t2==9: self.sucnum=self.sucnum+1 return ("测试成功") else: self.errnum=self.errnum+1 return ("测试失败") if __name__ == '__main__': resultdic={} bugdic={} obj=testcase_ind_a3() r1=obj.test_case5(2) if r1=="测试失败": # bugObj=bug_testframe() # bugObj.addbugresult("test_case1",r1) bugdic["test_case5"]=r1 resultdic["test_case5"]=r1 r2=obj.test_case6(3) if r2=="测试失败": # bugObj=bug_testframe() # bugObj.addbugresult("test_case2",r2) bugdic["test_case6"] = r2 resultdic["test_case6"]=r2 #obj.test_case1() # obj.test_case2() # print(resultdic) print("存放bug的数据字典",bugdic) print("存放结果的字典",resultdic) repobj=report_testframe() repobj.addtestreport(str(resultdic),str(obj.sucnum),str(obj.errnum)) print(obj.errnum) if obj.errnum>0: bugObj=bug_testframe() bugObj.addbugresult(bugdic)
atstudy_test_frame.py
# coding=gbk import datetime import smtplib from email.header import Header from email.mime.text import MIMEText import unittest2 import wx import csv import os #from atstudy_testframe.lib.HTMLTestRunner import HTMLTestRunner from atstudy_testframe.lib.HTMLTestRunner import HTMLTestRunner class atstudy_test_frame(): def __init__(self): self.app=wx.App() self.window=wx.Frame(None,title="atstudy测试框架v1.0",size=(500,230)) self.panel=wx.Panel(self.window) self.lbl_file=wx.StaticText(self.panel,label="测试框架配置文件") self.txt_file=wx.TextCtrl(self.panel,style=wx.TE_READONLY)#TE_READONLY为只读 self.but_open=wx.Button(self.panel,label="打开") self.but_run=wx.Button(self.panel,label="执行") self.but_clear=wx.Button(self.panel,label="重置") self.but_exit=wx.Button(self.panel,label="退出") #打开文件的本地路径初始化 self.configfile='' self.opt_csv_report=wx.RadioButton(self.panel,-1,"表格形式测试报告") self.opt_csv_report.SetValue(1) self.opt_htm_report=wx.RadioButton(self.panel,-1,label="HTML形式测试报告(只支持unittest框架)") self.chk_bug_report=wx.CheckBox(self.panel,label="是否生成bug报告") self.chk_bug_send = wx.CheckBox(self.panel, label="是否发送bug报告") #self.chk_bug_send.Show(False) def UI_layout(self): boxsizer1=wx.BoxSizer() boxsizer1.Add(self.lbl_file,flag=wx.ALL,border=10) boxsizer1.Add(self.txt_file,proportion=2,flag=wx.ALL,border=10) boxsizer2=wx.BoxSizer() boxsizer2.Add(self.opt_csv_report) boxsizer2.Add(self.chk_bug_report) boxsizer3=wx.BoxSizer() boxsizer3.Add(self.opt_htm_report,flag=wx.LEFT,border=1) boxsizer4=wx.BoxSizer() boxsizer4.Add(self.but_open,flag=wx.ALL,border=10) boxsizer4.Add(self.but_run,flag=wx.ALL,border=10) boxsizer4.Add(self.but_clear,flag=wx.ALL,border=10) boxsizer4.Add(self.but_exit,flag=wx.ALL,border=10) boxsizer6=wx.BoxSizer() #RESERVE_SPACE_EVEN_IF_HIDDEN为保存空间 boxsizer6.Add(self.chk_bug_send,flag=wx.RESERVE_SPACE_EVEN_IF_HIDDEN) #VERTICAL垂直布局 boxsizer5=wx.BoxSizer(wx.VERTICAL) boxsizer5.Add(boxsizer1,flag=wx.Top|wx.EXPAND,border=40) boxsizer5.Add(boxsizer2, flag=wx.ALL, border=10) boxsizer5.Add(boxsizer6,flag=wx.LEFT,border=130) boxsizer5.Add(boxsizer3,flag=wx.LEFT|wx.BOTTOM,border=10) boxsizer5.Add(boxsizer4) self.panel.SetSizer(boxsizer5) #控件触发 def UI_event(self): self.but_open.Bind(wx.EVT_BUTTON,self.openfile) # self.but_run.Bind(wx.EVT_BUTTON,self.readfile) self.but_run.Bind(wx.EVT_BUTTON, self.run_driver) self.but_clear.Bind(wx.EVT_BUTTON,self.resetfile) self.but_exit.Bind(wx.EVT_BUTTON, self.exitfile) self.opt_csv_report.Bind(wx.EVT_RADIOBUTTON,self.showbugreport) self.opt_htm_report.Bind(wx.EVT_RADIOBUTTON, self.hidbugreport) self.chk_bug_report.Bind(wx.EVT_CHECKBOX,self.showbugsend) self.chk_bug_send.Show(False) #bug邮件与bug报告单的联动效果,选择了bug报告单后才出现选择bug邮件的框 def showbugsend(self,event): if self.chk_bug_report.GetValue()==True: self.chk_bug_send.Show(True) else: self.chk_bug_send.Show(False) #csv报告与生成bug报告单的联动效果,选择了csv报告生成才出现选择bug报告的框 def showbugreport(self,event): if self.opt_csv_report.GetValue()==True: self.chk_bug_report.Show(True) #选择生成htm报告,bug报告单的框被屏蔽不出现 def hidbugreport(self,event): if self.opt_htm_report.GetValue()==True: self.chk_bug_report.Show(False) #点击打开按钮,选择文件 def openfile(self,event): self.dlg_open=wx.FileDialog(self.panel, message="打开文件", wildcard='*.csv', style=wx.FD_OPEN) if self.dlg_open.ShowModal()==wx.ID_OK: self.txt_file.AppendText(self.dlg_open.GetPath()) self.configfile=self.dlg_open.GetPath() # def readfile(self,event): # file=open(self.configfile,"r") # table=csv.reader(file) # for content in table: # print(content) def run_driver(self,event): #抓取配置文件框里的值,如果为空,弹出提示框报错 txtfile=self.txt_file.GetValue() if(txtfile==""): dlg=wx.MessageDialog(None,"必须选择配置文件","错误提示",wx.YES_DEFAULT|wx.ICON_QUESTION) if dlg.ShowModal()==wx.ID_OK: dlg.Destroy() return (0) #在下面建立一个driver_testframe类,实现csv报告,htm报告,csv中的生成bug报告, # csv中的生成bug报告后的发送报告到邮箱的触发 driverObj=driver_testframe() #如果选择了csv报告 if self.opt_csv_report.GetValue()==1: #选择csv报告后再选择生成bug报告单 if self.chk_bug_report.GetValue()==True: #设置生成bug单 createbugreport=1 #选择生成bug报告单后再选择发送bug邮件 if self.chk_bug_send.GetValue()==True: #生成bug报告发送邮件 sendemail=1 driverObj.runtestfile_csv_report_bug_send(self.configfile, createbugreport, sendemail) else: #生成bug报告不发送邮件 sendemail=0 driverObj.runtestfile_csv_report_bug(self.configfile, createbugreport) else: #不生成bug报告 createbugreport=0 driverObj.runtestfile_csv_report(self.configfile) #带着路径下的文件,bug单标识,bug邮件标识的参数,通过runtestfile_csv_report去实现具体执行过程 #选择htm报告单 elif self.opt_htm_report.GetValue()==1: #如果选择了htm报告单,用runtestfile_htm_report实现具体执行过程 driverObj.runtestfile_htm_report(self.configfile) # driverObj.runtestfile(self.configfile) #重置 def resetfile(self,event): self.txt_file.SetValue("") #关闭窗口 def exitfile(self,event): self.window.Close() def UI_show(self): #打开窗体 self.window.Show(True) self.app.MainLoop() #新建类,实现htm与csv报告的生成 class driver_testframe(): #生成htm报告 def runtestfile_htm_report(self,configfile): file=open(configfile,"r") table=csv.reader(file) #除去csv文件中的标题行 header=next(table) list = [] # 标准RUN的运行,其他的不运行 for content in table: if content[2] == "RUN": f = content[1] # print(f,content[3]) list.append(content[0] + ','+content[1]+','+content[3]) print("list的值为", list) # 排脚本执行优先级 list2 = [] for i in list: a = i.split(',') # print(a) list2.append(a) print("list2的值为",list2) # 优先级排序 list3 = sorted(list2, key=lambda i: i[2]) print("list3的值",list3) i = 1 for test in list3: print("0的值",test[0]) print("1的值",test[1]) test_suite = unittest2.defaultTestLoader.discover(test[1],test[0]) fp = open('D:\python\\atstudy_testframe\\atstudy_test_report\\unit_test1_report'+str(i)+'.htm', 'wb') #runner=HTMLTestRunner(stream=fp, title="api测试报告", description="测试情况") runner=HTMLTestRunner(stream=fp, title="api测试报告", description="测试情况").run(test_suite) i = i + 1 # 生成包含有bug报告与发送邮件的测试报告 def runtestfile_csv_report_bug_send(self,configfile,createbugreport,sendemail): #实例化发送bugemail类 sendbugObj=sendbug_testframe() #若选择了生成bug单 if createbugreport==1: bugObj=bug_testframe() #创建bug报告 bugObj.createbugreport() bugObj.writebugtitle() repObj=report_testframe() repObj.createreport() file = open(configfile, "r") table = csv.reader(file) #2创建测试报告的标题行(借助配置文件的标题行) repObj.writetitle() header = next(table) list = [] sucnum=0 errnum=0 startime=datetime.datetime.now() #标准RUN的运行,其他的不运行 for content in table: if content[2] == "RUN": f = content[1] # print(f,content[3]) list.append(content[0] + ',' + content[1]+ ',' + content[2]+ ',' + content[3]+ ',' + content[4]+ ',' + content[5]+ ',' + content[6]) print(list) #排脚本执行优先级 list2 = [] for i in list: a = i.split(',') # print(a) list2.append(a) #print(list2) list3 = sorted(list2, key=lambda i: i[3]) print("list3的值", list3) for test in list3: print(test[0]) #执行脚本 stros = ('python ' + test[1]) os.system(stros) #建立readtestresult方法,读取脚本生成结果放入tmp.txt r=repObj.readtestresult() print("测试结果",r) #把addtestreport方法中建立的tmp.txt文件中写入的测试结果读取出来,生成测试报告,写入testreport.csv中 repObj.writecontent(test[0],test[1],test[2],test[3],repObj.content) sucnum=sucnum+repObj.sucnum errnum=errnum+repObj.errnum #print("------",repObj.errnum) if repObj.errnum>0: #从临时bug文件中,获取相关的bug信息 bugresult=bugObj.readbugresult() #说明有执行失败的测试用例,从tmpbug文件中读取相关的内容写入bug报告 bugObj.writebugcontent(test[0],test[1],test[2],test[3],test[4],test[5],bugresult) #判断用户是否选择发送bug邮件 if sendemail==1: #如果选择发送bug邮件,调用发送bug邮件方法 #从临时的bug文件中获取bug内容 tmpfile = open("D:\python\\atstudy_testframe\\atstudy_bug_report\\tmpbug.txt", "r") bugcontent=tmpfile.read() #从配置文件中获取开发人员的邮箱 devemail=test[6] print("bug内容",bugcontent,"开发人员邮箱",devemail) sendbugObj.sendbugemail(bugcontent,devemail) #如果选择发送bug邮件,调用发送bug邮件方法 print(sucnum,errnum) endtime=datetime.datetime.now() difftime=(startime-endtime).microseconds print(difftime) #在测试报告中写入用例数,bug数,执行时间 repObj.writetotal(sucnum,errnum,difftime) def runtestfile_csv_report(self, configfile): repObj = report_testframe() repObj.createreport() file = open(configfile, "r") table = csv.reader(file) # 2创建测试报告的标题行(借助配置文件的标题行) repObj.writetitle() header = next(table) list = [] sucnum = 0 errnum = 0 startime = datetime.datetime.now() # 标准RUN的运行,其他的不运行 for content in table: if content[2] == "RUN": f = content[1] # print(f,content[3]) list.append( content[0] + ',' + content[1] + ',' + content[2] + ',' + content[3] + ',' + content[4] + ',' +content[5] + ',' + content[6]) print(list) # 排脚本执行优先级 list2 = [] for i in list: a = i.split(',') # print(a) list2.append(a) list3 = sorted(list2, key=lambda i: i[3]) print("list3的值", list3) for test in list3: print("执行的用例为",test[1]) # 执行脚本 stros = ('python ' + test[1]) os.system(stros) # 建立readtestresult方法,读取脚本生成结果放入tmp.txt r = repObj.readtestresult() print("测试结果", r) sucnum = sucnum + repObj.sucnum errnum = errnum + repObj.errnum # 把addtestreport方法中建立的tmp.txt文件中写入的测试结果读取出来,生成测试报告,写入testreport.csv中 repObj.writecontent(test[0], test[1], test[2], test[3], repObj.content) print("content打印结果",test[0], test[1], test[2], test[3]) # print("------",repObj.errnum) # 如果选择发送bug邮件,调用发送bug邮件方法 # 从临时的bug文件中获取bug内容 tmpfile = open("D:\python\\atstudy_testframe\\atstudy_bug_report\\tmpbug.txt", "r") bugcontent = tmpfile.read() print(sucnum, errnum) endtime = datetime.datetime.now() difftime = (startime - endtime).microseconds print(difftime) # 在测试报告中写入用例数,bug数,执行时间 repObj.writetotal(sucnum, errnum, difftime) def runtestfile_csv_report_bug(self, configfile, createbugreport): # 实例化发送bugemail类 sendbugObj = sendbug_testframe() # 若选择了生成bug单 bugObj = bug_testframe() # 创建bug报告 bugObj.createbugreport() bugObj.writebugtitle() repObj = report_testframe() repObj.createreport() file = open(configfile, "r") table = csv.reader(file) # 2创建测试报告的标题行(借助配置文件的标题行) repObj.writetitle() header = next(table) list = [] sucnum = 0 errnum = 0 startime = datetime.datetime.now() # 标准RUN的运行,其他的不运行 for content in table: if content[2] == "RUN": f = content[1] # print(f,content[3]) list.append( content[0] + ',' + content[1] + ',' + content[2] + ',' + content[3] + ',' + content[4] + ',' +content[5] + ',' + content[6]) print(list) # 排脚本执行优先级 list2 = [] for i in list: a = i.split(',') # print(a) list2.append(a) # print(list2) list3 = sorted(list2, key=lambda i: i[3]) print("list3的值", list3) for test in list3: print(test[1]) # 执行脚本 stros = ('python ' + test[1]) os.system(stros) # 建立readtestresult方法,读取脚本生成结果放入tmp.txt r = repObj.readtestresult() print("测试结果", r) # 把addtestreport方法中建立的tmp.txt文件中写入的测试结果读取出来,生成测试报告,写入testreport.csv中 repObj.writecontent(test[0], test[1], test[2], test[3], repObj.content) sucnum = sucnum + repObj.sucnum errnum = errnum + repObj.errnum # print("------",repObj.errnum) if repObj.errnum > 0: # 从临时bug文件中,获取相关的bug信息 bugresult = bugObj.readbugresult() # 说明有执行失败的测试用例,从tmpbug文件中读取相关的内容写入bug报告 bugObj.writebugcontent(test[0], test[1], test[2], test[3], test[4], test[5], bugresult) # 判断用户是否选择发送bug邮件 # 如果选择发送bug邮件,调用发送bug邮件方法 # 从临时的bug文件中获取bug内容 tmpfile = open("D:\python\\atstudy_testframe\\atstudy_bug_report\\tmpbug.txt", "r") bugcontent = tmpfile.read() print(sucnum, errnum) endtime = datetime.datetime.now() difftime = (startime - endtime).microseconds print(difftime) # 在测试报告中写入用例数,bug数,执行时间 repObj.writetotal(sucnum, errnum, difftime) #测试报告类的实现 class report_testframe(): #创建测试报告 def createreport(self): filepath="D:\python\\atstudy_testframe\\atstudy_test_report\\testreport.csv" if os.path.exists(filepath): os.remove(filepath) self.reportfile=open(filepath,"a",newline="") self.write=csv.writer(self.reportfile) #创建测试报告的title def writetitle(self): configfile=open("D:\python\\atstudy_testframe\\atstudy_test_config\\testcase.csv","r") table=csv.reader(configfile) title=list(table)[0] print("title的值为",title) self.write.writerow(title+["测试结论"]) self.reportfile.close() #把addtestreport方法中建立的tmp.txt文件中写入的测试结果读取出来,生成测试报告,写入testreport.csv中 def writecontent(self,casenum,casename,runstate,runseq,result): self.reportfile=open("D:\python\\atstudy_testframe\\atstudy_test_report\\testreport.csv","a",newline="") self.write=csv.writer(self.reportfile) self.write.writerow([casenum]+[casename]+[runstate]+[runseq]+[result]) self.reportfile.close() # 在测试报告中写入用例数,bug数,执行时间 def writetotal(self,sucnum,errnum,difftime): self.reportfile=open("D:\python\\atstudy_testframe\\atstudy_test_report\\testreport.csv","a",newline="") self.write=csv.writer(self.reportfile) totalnum=sucnum+errnum self.write.writerow(["测试用例总数"]+[str(totalnum)]+["条"]) self.write.writerow(["测试成功的用例总数"] + [str(sucnum)]+["条"]) self.write.writerow(["测试失败的用例总数"] + [str(errnum)]+['条']) self.write.writerow(["执行测试所需时间"] + [str(difftime)]+['微妙']) self.reportfile.close() #把py文件里的运行结果写到tmp.txt下 def addtestreport(self,content,sucnum,errnum): tmpfile=open("D:\python\\atstudy_testframe\\atstudy_test_report\\tmp.txt","w") tmpfile.write(content+"\n") tmpfile.write(sucnum+"\n") tmpfile.write(errnum+"\n") tmpfile.close() #建立readtestresult方法,读取脚本生成结果放入tmp.txt def readtestresult(self): tmpfile = open("D:\python\\atstudy_testframe\\atstudy_test_report\\tmp.txt", "r") result=tmpfile.read().split("\n") self.content=result[0] self.sucnum=int(result[1]) self.errnum=int(result[2]) print(self.content,self.sucnum,self.errnum) return result #bug类 class bug_testframe(): #创建bug报告 def createbugreport(self): filepath="D:\python\\atstudy_testframe\\atstudy_bug_report\\bugreport.csv" if os.path.exists(filepath): os.remove(filepath) self.bugfile=open(filepath,"a",newline="") self.write=csv.writer(self.bugfile) def writebugtitle(self): #从配置文件读取标题+测试结论 configfile=open("D:\python\\atstudy_testframe\\atstudy_test_config\\testcase3.csv") table=csv.reader(configfile) title=list(table)[0] print(title) self.write.writerow(title+["未通过的测试用例"]) self.bugfile.close() # 测试用例py文件中的bug结果值写入tmpbug.txt临时文件 def addbugresult(self,bugdic): tmpfile=open("D:\python\\atstudy_testframe\\atstudy_bug_report\\tmpbug.txt","w") tmpfile.write(str(bugdic)) tmpfile.close() #生成带有bug结果的测试报告 def writebugcontent(self, casenum, casename, runstate, runseq, discript, developer,bugresult): self.bugfile = open("D:\python\\atstudy_testframe\\atstudy_bug_report\\bugreport.csv", "a", newline="") self.write = csv.writer(self.bugfile) self.write.writerow([casenum] + [casename] + [runstate] + [runseq] + [discript]+[developer]+[bugresult]) self.bugfile.close() #读取tmpbug的内容 def readbugresult(self): tmpfile = open("D:\python\\atstudy_testframe\\atstudy_bug_report\\tmpbug.txt", "r") result = tmpfile.read() return result class sendbug_testframe(): def sendbugemail(self,bugcontent,devemail): smtp = smtplib.SMTP("smtp.qq.com") # 登录邮箱 smtp.login("[email protected]", "qxzfltselnapdige") print("登录成功") # 设置邮件的发送内容 msg = MIMEText(bugcontent, "html", "utf-8") # 设置邮件的标题 msg["subject"] = Header("测试邮件发送") # 指定发件人 msg["from"] = "[email protected]" msg["to"] = devemail # 进行邮件发送 smtp.sendmail(msg["from"], msg["to"], msg.as_string()) # 关闭邮件服务器 smtp.close() if __name__ == '__main__': Obj=atstudy_test_frame() Obj.UI_layout() Obj.UI_event() Obj.UI_show()
测试报告生成截图
bug报告生成截图
邮件生成截图