Unittest框架+ddt数据驱动+HTMLTestRunner+sendmail(自动发送测试报告)+git+Jenkins
本次写的是针对有代码基础的,没基础建议先去学基础,以下所有描述内容都是我已经在公司项目实践成功的!仅供参考
整体思路:
1、接口自动化用的是Python中unittest框架
2、所有的测试数据用例存放Excel表
3、封装一套读取和写入的Excel方法
4、重写request方法(为了从Excel读取数据后对数据作分析和判断并在测试报告生成相关信息)
5、通过HTMLTestRunner运行测试用例生成网页版报告
6、将自动化脚本放到公司git上,方便其他人员获取你的代码进行编写脚本,后面会具体讲如何获取代码和提交代码(让运维人员给你开通个git账号,自己注册登录就可以了)
7、通过Jenkins构建任务,定时自动运行git上自动化脚本,后面会具体讲如何配置Jenkins
先看看我的接口自动化整个目录结构和每个文件具体是干嘛的:
一、读取表格的代码:
1 import xlrd,os,copy 2 3 import sys,os 4 5 #这三行代码是解决文件路径问题 6 7 curPath = os.path.abspath(os.path.dirname(__file__)) 8 9 rootPath = os.path.split(curPath)[0] 10 11 sys.path.append(rootPath) 12 13 class ExcelUtil(): 14 15 list=[] 16 17 list1 = [] 18 19 def __init__(self,excelpath,sheetname='Sheet1'): 20 21 self.data=xlrd.open_workbook(excelpath) 22 23 self.table=self.data.sheet_by_name(sheetname) 24 25 #获取第一行作为key值 26 27 self.keys=self.table.row_values(0) 28 29 #获取总行数 30 31 self.rowNum=self.table.nrows 32 33 #获取总列数 34 35 self.colNum=self.table.ncols 36 37 38 39 #此方法有俩个用处:1、获取关闭或打开的case 2、不同模块的用例也可以通过该方法区分开来 40 41 def open_case(self): 42 43 exceldata = ExcelUtil(os.path.abspath(rootPath+'/Case/Ddt_case_api/TestCase.xlsx'), 'Sheet1') 44 45 list = [] 46 47 list1 = [] 48 49 list2=[] 50 51 for i in exceldata.dict_data(): 52 53 a = i['control_case'] # 这是在Excel加的开关case的字段 54 55 if a == '': 56 57 list.append(i) 58 59 elif a=='mobile_请先登录': 60 61 list1.append(i) 62 63 elif a=='B_请先登录': 64 65 list2.append(i) 66 67 return list,list1,list2 68 69 # print(len(list)) 70 71 def dict_data(self): 72 73 if self.rowNum<=1: 74 75 print('总行数小于1') 76 77 else: 78 79 r=[] 80 81 j=1 82 83 for i in range(self.rowNum-1): 84 85 s={} 86 87 s['rowNum']=i+2 88 89 values=self.table.row_values(j) 90 91 for x in range(self.colNum): 92 93 s[self.keys[x]]=values[x] 94 95 r.append(s) 96 97 j+=1 98 99 return r 100 101 #通过下面这个入口进行调试 102 103 if __name__=='__main__': 104 105 a=ExcelUtil('D:\Business_ManageMent\Case\Ddt_case_api\TestCase.xlsx') 106 107 b=a.open_case() 108 109 print(b)
二、写入表格代码:
1 from openpyxl import load_workbook 2 3 import openpyxl 4 5 import xlrd 6 7 8 9 def Copy_excel(exclepath1,excelpath2): 10 11 #把excle1数据复制到excel2 12 13 wb2=openpyxl.Workbook() 14 15 wb2.save(excelpath2) 16 17 wb1=load_workbook(exclepath1) 18 19 wb2=load_workbook(excelpath2) 20 21 sheets1=wb1.sheetnames 22 23 sheets2=wb2.sheetnames 24 25 sheet1=wb1[sheets1[0]] 26 27 sheet2=wb2[sheets2[0]] 28 29 maxrow=sheet1.max_row 30 31 maxcolum=sheet1.max_column 32 33 for m in range(1,maxrow+1): 34 35 for n in range(97,97+maxcolum): 36 37 n=chr(n) 38 39 i='%s%d'%(n,m) 40 41 cell1=sheet1[i].value 42 43 sheet2[i]=cell1 44 45 wb2.save(excelpath2) 46 47 wb1.close() 48 49 wb2.close() 50 51 class Write_excel(): 52 53 def __init__(self,filename): 54 55 self.filename=filename 56 57 self.wb=load_workbook(self.filename) 58 59 #激活sheet 60 61 self.ws=self.wb.active 62 63 def write(self,row_n,col_n,value): 64 65 self.ws.cell(row_n,col_n).value=value 66 67 self.wb.save(self.filename) 68 69 70 71 72 73 #通过下面入口进行调试 74 75 if __name__=='__main__': 76 77 Copy_excel('D:\Business_ManageMent\Case\Ddt_case_api\TestCase.xlsx','D:\Business_ManageMent\Case\\result.xlsx') 78 79 wt=Write_excel('D:\Business_ManageMent\Case\\result.xlsx') 80 81 wt.write(1,2,'hello')
三、重写request方法及将接口返回结果根据自己的需要写入拷贝的那张Excel表中
1 import json 2 import requests 3 from Tool_class.read_excel_fz import ExcelUtil 4 from Tool_class.writeexcel_fz import Copy_excel, Write_excel 5 6 7 def send_requests(s, testdata): 8 '''封装requests请求''' 9 #获取Excel标格中表头为method的数据 10 method = testdata["method"] 11 # 获取Excel标格中表头为url的数据 12 url = testdata["url"] 13 try: 14 #eval函数可以将读取到的参数内容转化成字典格式 15 # 获取Excel标格中表头为params的数据 16 params = eval(testdata["params"]) 17 except: 18 params = None 19 # 请求头部headers 20 try: 21 # 获取Excel标格中表头为headers的数据 22 headers = eval(testdata["headers"]) 23 print("请求头部:%s" % headers) 24 except: 25 headers = None 26 27 28 # post请求body类型 29 # 获取Excel标格中表头为type的数据 30 type = testdata["type"] 31 # 获取Excel标格中表头为id的数据 32 test_nub = testdata['id'] 33 print("*******正在执行用例:----- %s ----**********" % test_nub) 34 print("请求方式:%s, 请求url:%s" % (method, url)) 35 print("请求params:%s" % params) 36 # post请求body内容 37 try: 38 # 获取Excel标格中表头为body的数据 39 bodydata = eval(testdata["body"]) 40 except: 41 bodydata = {} 42 # 判断传data数据还是json 43 if type == "json": 44 #json.dumps将字典数据转成json格式,因为不同的接口传递参数是不同的,有的是传data,有的传json 45 body= json.dumps(bodydata) 46 elif type == "data": 47 body = bodydata 48 else: 49 body = bodydata 50 51 if type=='json': 52 print("post请求body类型为:%s ,body内容为:%s" % (type,body)) 53 elif method=='post': 54 print("post请求body类型为:%s ,body内容为:%s" % (type,body)) 55 verify = False 56 res = {} # 接受返回数据 57 58 try: 59 r = s.request(method=method, 60 url=url, 61 params=params, 62 headers=headers, 63 data=body, 64 verify=verify 65 ) 66 print("页面返回信息:%s" % r.json()) 67 res['id'] = testdata['id'] 68 res['rowNum'] = testdata['rowNum'] 69 res["statuscode"] = str(r.status_code) # 状态码转成str 70 res["text"] = r.json() 71 res["times"] = str(r.elapsed.total_seconds()) # 接口请求时间转str 72 if res["statuscode"] != "200": 73 res["error"] = "服务错误,接口未请求成功" 74 res["msg"] = str(res["text"]) 75 else: 76 res["error"] = "" 77 res["msg"] = "" 78 if testdata["checkpoint"] == res["text"]['msg']: 79 res["result"] = "pass" 80 print("用例测试结果: %s---->%s" % (test_nub, res["result"])) 81 else: 82 res["result"] = "fail" 83 return res 84 except Exception as msg: 85 res["msg"] = str(msg) 86 return res 87 #将运行返回的结果,根据自己需要,需要要哪些结果就把哪些结果写入拷贝的那份Excel中 88 def wirte_result(result, filename="D:\Business_ManageMent\Case\\result.xlsx"): 89 # 返回结果的行数row_nub 90 row_nub = result['rowNum'] 91 # 写入statuscode 92 wt = Write_excel(filename) 93 wt.write(row_nub, 7, result['statuscode']) # 写入返回状态码statuscode,第8列 94 wt.write(row_nub, 12, result['times']) # 耗时 95 wt.write(row_nub, 14, result['error']) # 状态码非200时的返回信息 96 wt.write(row_nub, 13, result['result']) # 测试结果 pass 还是fail 97 wt.write(row_nub, 15, result['msg']) # 抛异常
四、定义发送邮件和创建测试用例套件
1 import time,os 2 import smtplib 3 import unittest 4 from Commons import HTMLTestRunner_jpg 5 from email.header import Header 6 from email.mime.text import MIMEText 7 from email.mime.multipart import MIMEMultipart 8 import email.mime.multipart 9 from email.mime.application import MIMEApplication 10 from Case import * 11 12 # test_dir = os.path.abspath(os.path.join(os.getcwd(), "..")) 13 # now = time.strftime('%y_%m_%d %H_%M_%S') 14 # filename = (os.path.abspath('../Report') + '\\' + now + 'result.html') 15 # print(filename) 16 # fp = open(filename, 'wb') 17 import sys,os 18 curPath = os.path.abspath(os.path.dirname(__file__)) 19 rootPath = os.path.split(curPath)[0] 20 sys.path.append(rootPath) 21 #定义发送邮件 22 class Send(): 23 def __init__(self): 24 self.flie_dir=rootPath+'\Report' 25 self.lists = os.listdir(self.flie_dir) 26 #将所有的报告按时间从小到大大排序 27 self.lists.sort(key=lambda fn: os.path.getmtime(self.flie_dir + '\\' + fn)) 28 #取报告集合中最后一个报告即为最新的测试报告 29 self.new_file = os.path.join(self.flie_dir, self.lists[-1]) 30 def send_mail(self): 31 now=time.strftime('%y:%m:%d:%H:%M:%S') 32 sender = '1063126729@qq.com' 33 recever= 'steve@wemart.cn' 34 msg = MIMEMultipart() 35 content = '最新接口测试报告,详情请下载附件查看,生成时间为:%s'%(now) 36 txt = email.mime.text.MIMEText(content, 'plain', 'utf-8') 37 msg.attach(txt) 38 msg['Subject']='接口自动化测试报告' 39 msg['date']=now 40 #添加附件 41 att = MIMEText(open(self.new_file, "rb").read(), "base64", "utf-8") 42 att["Content-Type"] = "application/octet-stream" 43 att["Content-Disposition"] = 'attachment; filename= "Report.html"' 44 msg.attach(att) 45 server=smtplib.SMTP_SSL(port=465) 46 server.connect('smtp.qq.com') 47 server.login('1063126729@qq.com','lhrcqszwzqafbcjf') 48 server.sendmail(sender,recever,msg.as_string()) 49 server.quit() 50 print('邮件已发送') 51 #创建一个测试套件,将所有的用例添加到测试套件 52 def creatsuit(slef): 53 test_dir =rootPath+'\Case' 54 suit=unittest.TestSuite() 55 discover=unittest.defaultTestLoader.discover(test_dir,pattern='test*.py',top_level_dir=None) 56 for test_suit in discover: 57 for case in test_suit: 58 suit.addTest(case) 59 return suit
这里说明一下,excel表格自己新建一份,名字命名好,表头各个字段自己喜欢命名啥就命名啥,但注意代码中涉及到表头字段的也要相应调整,保持俩者一致。下面我贴出我存放用例的excel表格样式,供参考:
A:控制开关case B:case名称 C:接口请求方法 D:接口地址 E:传参类型 F:请求头 G:状态码 H:检查点 I:get请求是传的参数 J:post请求时传的参数 K可以不要,这是我当时调试用的
L:接口响应时间 M:运行结果失败获成功 N:提示接口报错 O:接口返回的报错信息 其中G、L、M、N、O是不用填写的,这是为了复制该份表格时,要写入数据到复制的那份表格中用的
五、前四部分都是一些封装的东西,都是为了第五部分调用准备的,下面的代码是利用unittest框架去组织测试用例,因为我通过ddt数据驱动的,所以这部分代码就比较简洁了,如果你把测试数据都写在代码中,这是不利于维护的,看上去也很繁琐,几千条测试用例那要写多少
1 import unittest 2 import ddt 3 import os 4 import requests 5 from Commons import base_api 6 from Tool_class import read_excel_fz 7 from Tool_class import writeexcel_fz 8 from Case.Hand_code_case.Login_case.Test_stor_login02 import * 9 import os,copy 10 11 #获取当前文件位置路径 12 curpath = os.path.dirname(os.path.realpath(__file__)) 13 # 获取TestCase.xlsx路径 14 testxlsx = os.path.join(curpath, "TestCase.xlsx") 15 #获取curpath位置的上一层目录位置 16 report_path = os.path.join(os.path.dirname(curpath)) 17 #获取测试结果表格的目录位置 18 reportxlsx = os.path.join(report_path, "result.xlsx") 19 #创建读取表格的对象 20 testdata = read_excel_fz.ExcelUtil(testxlsx) 21 #获取表格中需要运行的数据或不需要运行的数据 22 cases=testdata.open_case() 23 #表格中打开的case 24 case=cases[0] 25 #表格中关闭的case 26 case_mobile=cases[1] 27 28 29 @ddt.ddt 30 class Test_api(unittest.TestCase): 31 u'''B2C-API''' 32 @classmethod 33 def setUpClass(cls): 34 # 如果有登录的话,就在这里先登录了 35 cls.s = requests.Session() 36 # 复制xlsx 37 writeexcel_fz.Copy_excel(testxlsx, reportxlsx) 38 39 #采用装饰器,在运行case之前都会先运行这个,这里的case是表格里打开的用例,也就是我需要运行的数据 40 @ddt.data(*case) 41 def test_api_01(self, data): 42 #先复制excel数据到Case文件夹下面 43 res = base_api.send_requests(self.s, data) 44 base_api.wirte_result(res, filename=reportxlsx) 45 #检查点 checkpoint 46 check = data["checkpoint"] 47 print("检查点->:%s"%check) 48 #返回结果 49 res_text = res["text"] 50 print("返回实际结果->:%s"%res_text) 51 #将接口返回的结果的键和值取到,通过键是否存在,再利用返回的值去和预期结果做断言 52 for m,n in res_text.items(): 53 if m=='data' and m=='msg': 54 self.assertTrue(res_text['data']!=None) 55 self.assertTrue(res_text['msg'] == check) 56 elif 'data' not in m: 57 self.assertTrue(res_text['msg']==check)
六、上面将用例组织好了,接下来就是通过HTMLTestRunner模块运行并生成报告了,注:HTMLTestRunner模块自己去百度下载,可以将内容直接复制,然后在你的工程目录下建一个py文件将内容拷贝进去即可
1 import sys,os 2 curPath = os.path.abspath(os.path.dirname(__file__)) 3 rootPath = os.path.split(curPath)[0] 4 sys.path.append(rootPath) 5 6 import unittest,time,os 7 from Commons import HTMLTestRunner_jpg 8 from email.header import Header 9 from email.mime.text import MIMEText 10 from Commons.send_mail_report import Send 11 12 #定义一个当前时间戳 13 now = time.strftime('%y_%m_%d %H_%M_%S') 14 #以时间给报告命名,这样就不会重复了 15 filename = rootPath+'\Report'+'\\'+ now + 'result.html' 16 fp=open(filename,'wb') 17 a = Send() 18 runner = HTMLTestRunner_jpg.HTMLTestRunner(stream=fp, title='测试报告', description='执行情况:') 19 runner.run(a.creatsuit()) 20 fp.close() 21 #调用发送邮件的方法 22 a.send_mail()
七、Jenkins配置
然后回到任务首页,点击任务后面按钮立即构建,打开控制台即可查看运行记录和结果,如图:
以上所有的步骤已经完成了整个项目的构建,大家针对自己的项目可以拿上面的代码加以修改,其实最重要的是思路和良好的代码基础,我没有针对工具安装进行详细说,这个自己百度!自动化并不难,教程也很多,要学会加以总结并融汇贯通。后期主要跟新我学Python的历程,从基础到高级,再到利用Python实战做项目,欢迎关注