python+requests+excel+unittest+ddt接口自動化數據驅動並生成html報告


1.環境准備:

  python3.6
  requests
  xlrd
  openpyxl
  HTMLTestRunner_api

2.目前實現的功能:

  封裝requests請求方法
  在excel填寫接口請求參數
  運行完后,重新生成一個excel報告,結果寫入excel
  用unittest+ddt數據驅動模式執行
  HTMLTestRunner生成可視化的html報告
  對於沒有關聯的單個接口請求是可以批量執行的,需要登錄的話寫到setUpclass里的session里保持cookies
  token關聯的不能實現
  logging日志文件暫時未加入

3.目前已知的缺陷:

  無法實現參數關聯:上個請求的結果是下個請求的參數,如token
  接口請求參數名有重復的,目前未處理,如key1=value1&key1=value2,兩個key都一樣,這種需要用元組存儲,目前暫時未判斷
  生成的excel樣式未處理,后期慢慢優化樣式
  python新手可能遇到模塊導入報錯問題

項目結構

excel測試數據

xlrd讀excel數據

1.先從excel里面讀取測試數據,返回字典格式

 1 # coding:utf-8
 2 
 3 # 作者:上海-悠悠
 4 # QQ群:226296743
 5 
 6 import xlrd
 7 class ExcelUtil():
 8     def __init__(self, excelPath, sheetName="Sheet1"):
 9         self.data = xlrd.open_workbook(excelPath)
10         self.table = self.data.sheet_by_name(sheetName)
11         # 獲取第一行作為key值
12         self.keys = self.table.row_values(0)
13         # 獲取總行數
14         self.rowNum = self.table.nrows
15         # 獲取總列數
16         self.colNum = self.table.ncols
17 
18     def dict_data(self):
19         if self.rowNum <= 1:
20             print("總行數小於1")
21         else:
22             r = []
23             j = 1
24             for i in list(range(self.rowNum-1)):
25                 s = {}
26                 # 從第二行取對應values值
27                 s['rowNum'] = i+2
28                 values = self.table.row_values(j)
29                 for x in list(range(self.colNum)):
30                     s[self.keys[x]] = values[x]
31                 r.append(s)
32                 j += 1
33             return r
34 
35 if __name__ == "__main__":
36     filepath = "debug_api.xlsx"
37     sheetName = "Sheet1"
38     data = ExcelUtil(filepath, sheetName)
39     print(data.dict_data())
40 openpyxl寫入數據
41 
42 1.再封裝一個寫入excel數據的方法
43 
44 # coding:utf-8
45 from openpyxl import load_workbook
46 import openpyxl
47 
48 # 作者:上海-悠悠
49 # QQ群:226296743
50 
51 def copy_excel(excelpath1, excelpath2):
52     '''復制excek,把excelpath1數據復制到excelpath2'''
53     wb2 = openpyxl.Workbook()
54     wb2.save(excelpath2)
55     # 讀取數據
56     wb1 = openpyxl.load_workbook(excelpath1)
57     wb2 = openpyxl.load_workbook(excelpath2)
58     sheets1 = wb1.sheetnames
59     sheets2 = wb2.sheetnames
60     sheet1 = wb1[sheets1[0]]
61     sheet2 = wb2[sheets2[0]]
62     max_row = sheet1.max_row         # 最大行數
63     max_column = sheet1.max_column   # 最大列數
64 
65     for m in list(range(1,max_row+1)):
66         for n in list(range(97,97+max_column)):   # chr(97)='a'
67             n = chr(n)                            # ASCII字符
68             i ='%s%d'% (n, m)                     # 單元格編號
69             cell1 = sheet1[i].value               # 獲取data單元格數據
70             sheet2[i].value = cell1               # 賦值到test單元格
71 
72     wb2.save(excelpath2)                 # 保存數據
73     wb1.close()                          # 關閉excel
74     wb2.close()
75 
76 class Write_excel(object):
77     '''修改excel數據'''
78     def __init__(self, filename):
79         self.filename = filename
80         self.wb = load_workbook(self.filename)
81         self.ws = self.wb.active  # 激活sheet
82 
83     def write(self, row_n, col_n, value):
84         '''寫入數據,如(2,3,"hello"),第二行第三列寫入數據"hello"'''
85         self.ws.cell(row_n, col_n).value = value
86         self.wb.save(self.filename)
87 
88 if __name__ == "__main__":
89     copy_excel("debug_api.xlsx", "testreport.xlsx")
90     wt = Write_excel("testreport.xlsx")
91     wt.write(4, 5, "HELLEOP")
92     wt.write(4, 6, "HELLEOP")

封裝request請求方法

1.把從excel讀處理的數據作為請求參數,封裝requests請求方法,傳入請求參數,並返回結果

2.為了不污染測試的數據,出報告的時候先將測試的excel復制都應該新的excel

3.把測試返回的結果,在新的excel里面寫入數據

 1 # coding:utf-8
 2 import json
 3 import requests
 4 from excelddtdriver.common.readexcel import ExcelUtil
 5 from excelddtdriver.common.writeexcel import copy_excel, Write_excel
 6 
 7 # 作者:上海-悠悠
 8 # QQ群:226296743
 9 
10 
11 def send_requests(s, testdata):
12     '''封裝requests請求'''
13     method = testdata["method"]
14     url = testdata["url"]
15     # url后面的params參數
16     try:
17         params = eval(testdata["params"])
18     except:
19         params = None
20     # 請求頭部headers
21     try:
22         headers = eval(testdata["headers"])
23         print("請求頭部:%s" % headers)
24     except:
25         headers = None
26     # post請求body類型
27     type = testdata["type"]
28 
29     test_nub = testdata['id']
30     print("*******正在執行用例:-----  %s  ----**********" % test_nub)
31     print("請求方式:%s, 請求url:%s" % (method, url))
32     print("請求params:%s" % params)
33 
34     # post請求body內容
35     try:
36         bodydata = eval(testdata["body"])
37     except:
38         bodydata = {}
39 
40     # 判斷傳data數據還是json
41     if type == "data":
42         body = bodydata
43     elif type == "json":
44         body = json.dumps(bodydata)
45     else:
46         body = bodydata
47     if method == "post": print("post請求body類型為:%s ,body內容為:%s" % (type, body))
48 
49     verify = False
50     res = {}   # 接受返回數據
51 
52     try:
53         r = s.request(method=method,
54                       url=url,
55                       params=params,
56                       headers=headers,
57                       data=body,
58                       verify=verify
59                        )
60         print("頁面返回信息:%s" % r.content.decode("utf-8"))
61         res['id'] = testdata['id']
62         res['rowNum'] = testdata['rowNum']
63         res["statuscode"] = str(r.status_code)  # 狀態碼轉成str
64         res["text"] = r.content.decode("utf-8")
65         res["times"] = str(r.elapsed.total_seconds())   # 接口請求時間轉str
66         if res["statuscode"] != "200":
67             res["error"] = res["text"]
68         else:
69             res["error"] = ""
70         res["msg"] = ""
71         if testdata["checkpoint"] in res["text"]:
72             res["result"] = "pass"
73             print("用例測試結果:   %s---->%s" % (test_nub, res["result"]))
74         else:
75             res["result"] = "fail"
76         return res
77     except Exception as msg:
78         res["msg"] = str(msg)
79         return res
80 
81 def wirte_result(result, filename="result.xlsx"):
82     # 返回結果的行數row_nub
83     row_nub = result['rowNum']
84     # 寫入statuscode
85     wt = Write_excel(filename)
86     wt.write(row_nub, 8, result['statuscode'])       # 寫入返回狀態碼statuscode,第8列
87     wt.write(row_nub, 9, result['times'])            # 耗時
88     wt.write(row_nub, 10, result['error'])            # 狀態碼非200時的返回信息
89     wt.write(row_nub, 12, result['result'])           # 測試結果 pass 還是fail
90     wt.write(row_nub, 13, result['msg'])           # 拋異常
91 
92 if __name__ == "__main__":
93     data = ExcelUtil("debug_api.xlsx").dict_data()
94     print(data[0])
95     s = requests.session()
96     res = send_requests(s, data[0])
97     copy_excel("debug_api.xlsx", "result.xlsx")
98     wirte_result(res, filename="result.xlsx")

測試用例unittest+ddt

1.測試用例用unittest框架組建,並用ddt數據驅動模式,批量執行用例

 1 # coding:utf-8
 2 import unittest
 3 import ddt
 4 import os
 5 import requests
 6 from excelddtdriver.common import base_api
 7 from excelddtdriver.common import readexcel
 8 from excelddtdriver.common import writeexcel
 9 
10 # 作者:上海-悠悠
11 # QQ群:226296743
12 
13 # 獲取demo_api.xlsx路徑
14 curpath = os.path.dirname(os.path.realpath(__file__))
15 testxlsx = os.path.join(curpath, "demo_api.xlsx")
16 
17 # 復制demo_api.xlsx文件到report下
18 report_path = os.path.join(os.path.dirname(curpath), "report")
19 reportxlsx = os.path.join(report_path, "result.xlsx")
20 
21 testdata = readexcel.ExcelUtil(testxlsx).dict_data()
22 @ddt.ddt
23 class Test_api(unittest.TestCase):
24     @classmethod
25     def setUpClass(cls):
26         cls.s = requests.session()
27         # 如果有登錄的話,就在這里先登錄了
28         writeexcel.copy_excel(testxlsx, reportxlsx) # 復制xlsx
29 
30     @ddt.data(*testdata)
31     def test_api(self, data):
32         # 先復制excel數據到report
33         res = base_api.send_requests(self.s, data)
34 
35         base_api.wirte_result(res, filename=reportxlsx)
36         # 檢查點 checkpoint
37         check = data["checkpoint"]
38         print("檢查點->:%s"%check)
39         # 返回結果
40         res_text = res["text"]
41         print("返回實際結果->:%s"%res_text)
42         # 斷言
43         self.assertTrue(check in res_text)
44 
45 if __name__ == "__main__":
46     unittest.main()

生成報告

1.用HTMLTestRunner生成html報告,我這里改了下名稱,改成了HTMLTestRunner_api.py
此文件跟selenium的報告是通用的,github可下載https://github.com/yoyoketang/selenium_report/tree/master/selenium_report

 1 # coding=utf-8
 2 import unittest
 3 import time
 4 from excelddtdriver.common import HTMLTestRunner_api
 5 import os
 6 
 7 # 作者:上海-悠悠
 8 # QQ群:226296743
 9 
10 curpath = os.path.dirname(os.path.realpath(__file__))
11 report_path = os.path.join(curpath, "report")
12 if not os.path.exists(report_path): os.mkdir(report_path)
13 case_path = os.path.join(curpath, "case")
14 
15 def add_case(casepath=case_path, rule="test*.py"):
16     '''加載所有的測試用例'''
17     # 定義discover方法的參數
18     discover = unittest.defaultTestLoader.discover(casepath,
19                                                   pattern=rule,)
20 
21     return discover
22 
23 def run_case(all_case, reportpath=report_path):
24     '''執行所有的用例, 並把結果寫入測試報告'''
25     htmlreport = reportpath+r"\result.html"
26     print("測試報告生成地址:%s"% htmlreport)
27     fp = open(htmlreport, "wb")
28     runner = HTMLTestRunner_api.H全部折疊 折疊標題:
29 View Code
30   顯示行號    行內代碼
31 TMLTestRunner(stream=fp,
32                                                verbosity=2,
33                                                title="測試報告",
34                                                description="用例執行情況")
35 
36     # 調用add_case函數返回值
37     runner.run(all_case)
38     fp.close()
39 
40 if __name__ == "__main__":
41     cases = add_case()
42     run_case(cases)

2.生成的excel報告

3.生成的html報告

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM