Unittest框架+ddt數據驅動+HTMLTestRunner+sendmail(自動發送測試報告)+git+Jenkins

本次寫的是針對有代碼基礎的,沒基礎建議先去學基礎,如下全部描述內容都是我已經在公司項目實踐成功的!僅供參考html

總體思路:
一、接口自動化用的是Python中unittest框架
二、全部的測試數據用例存放Excel表
三、封裝一套讀取和寫入的Excel方法
四、重寫request方法(爲了從Excel讀取數據後對數據做分析和判斷並在測試報告生成相關信息)git

五、經過HTMLTestRunner運行測試用例生成網頁版報告
六、將自動化腳本放到公司git上,方便其餘人員獲取你的代碼進行編寫腳本,後面會具體講如何獲取代碼和提交代碼(讓運維人員給你開通個git帳號,本身註冊登陸就能夠了)
七、經過Jenkins構建任務,定時自動運行git上自動化腳本,後面會具體講如何配置Jenkinsjson

 

 

 

先看看個人接口自動化整個目錄結構和每一個文件具體是幹嗎的:api

 

1、讀取表格的代碼:app

  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     #此方法有倆個用處:一、獲取關閉或打開的case 二、不一樣模塊的用例也能夠經過該方法區分開來
 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)

 

 

 

2、寫入表格代碼:框架

 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')


 

 

3、重寫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'])              # 拋異常

 

4、定義發送郵件和建立測試用例套件函數

 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能夠不要,這是我當時調試用的post

L:接口響應時間  M:運行結果失敗獲成功   N:提示接口報錯     O:接口返回的報錯信息     其中G、L、M、N、O是不用填寫的,這是爲了複製該份表格時,要寫入數據到複製的那份表格中用的

5、前四部分都是一些封裝的東西,都是爲了第五部分調用準備的,下面的代碼是利用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)

6、上面將用例組織好了,接下來就是經過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()
 
 

 

 

 7、Jenkins配置

 

 

 

 

而後回到任務首頁,點擊任務後面按鈕當即構建,打開控制檯便可查看運行記錄和結果,如圖:

 

以上全部的步驟已經完成了整個項目的構建,你們針對本身的項目能夠拿上面的代碼加以修改,其實最重要的是思路和良好的代碼基礎,我沒有針對工具安裝進行詳細說,這個本身百度!自動化並不難,教程也不少,要學會加以總結並融匯貫通。後期主要跟新我學Python的歷程,從基礎到高級,再到利用Python實戰作項目,歡迎關注

相關文章
相關標籤/搜索