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

前言

1.環境準備:html

  • python3.6
  • requests
  • xlrd
  • openpyxl
  • HTMLTestRunner_api

2.目前實現的功能:python

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

3.目前已知的缺陷:json

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

項目結構

excel測試數據

xlrd讀excel數據

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

# coding:utf-8

# 做者:上海-悠悠
# QQ羣:226296743

import xlrd
class ExcelUtil():
    def __init__(self, excelPath, sheetName="Sheet1"):
        self.data = xlrd.open_workbook(excelPath)
        self.table = self.data.sheet_by_name(sheetName)
        # 獲取第一行做爲key值
        self.keys = self.table.row_values(0)
        # 獲取總行數
        self.rowNum = self.table.nrows
        # 獲取總列數
        self.colNum = self.table.ncols

    def dict_data(self):
        if self.rowNum <= 1:
            print("總行數小於1")
        else:
            r = []
            j = 1
            for i in list(range(self.rowNum-1)):
                s = {}
                # 從第二行取對應values值
                s['rowNum'] = i+2
                values = self.table.row_values(j)
                for x in list(range(self.colNum)):
                    s[self.keys[x]] = values[x]
                r.append(s)
                j += 1
            return r

if __name__ == "__main__":
    filepath = "debug_api.xlsx"
    sheetName = "Sheet1"
    data = ExcelUtil(filepath, sheetName)
    print(data.dict_data())

openpyxl寫入數據

1.再封裝一個寫入excel數據的方法cookie

# coding:utf-8
from openpyxl import load_workbook
import openpyxl

# 做者:上海-悠悠
# QQ羣:226296743

def copy_excel(excelpath1, excelpath2):
    '''複製excek,把excelpath1數據複製到excelpath2'''
    wb2 = openpyxl.Workbook()
    wb2.save(excelpath2)
    # 讀取數據
    wb1 = openpyxl.load_workbook(excelpath1)
    wb2 = openpyxl.load_workbook(excelpath2)
    sheets1 = wb1.sheetnames
    sheets2 = wb2.sheetnames
    sheet1 = wb1[sheets1[0]]
    sheet2 = wb2[sheets2[0]]
    max_row = sheet1.max_row         # 最大行數
    max_column = sheet1.max_column   # 最大列數

    for m in list(range(1,max_row+1)):
        for n in list(range(97,97+max_column)):   # chr(97)='a'
            n = chr(n)                            # ASCII字符
            i ='%s%d'% (n, m)                     # 單元格編號
            cell1 = sheet1[i].value               # 獲取data單元格數據
            sheet2[i].value = cell1               # 賦值到test單元格

    wb2.save(excelpath2)                 # 保存數據
    wb1.close()                          # 關閉excel
    wb2.close()

class Write_excel(object):
    '''修改excel數據'''
    def __init__(self, filename):
        self.filename = filename
        self.wb = load_workbook(self.filename)
        self.ws = self.wb.active  # 激活sheet

    def write(self, row_n, col_n, value):
        '''寫入數據,如(2,3,"hello"),第二行第三列寫入數據"hello"'''
        self.ws.cell(row_n, col_n).value = value
        self.wb.save(self.filename)

if __name__ == "__main__":
    copy_excel("debug_api.xlsx", "testreport.xlsx")
    wt = Write_excel("testreport.xlsx")
    wt.write(4, 5, "HELLEOP")
    wt.write(4, 6, "HELLEOP")

封裝request請求方法

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

2.爲了避免污染測試的數據,出報告的時候先將測試的excel複製都應該新的excelapp

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

# coding:utf-8
import json
import requests
from excelddtdriver.common.readexcel import ExcelUtil
from excelddtdriver.common.writeexcel import copy_excel, Write_excel

# 做者:上海-悠悠
# QQ羣:226296743


def send_requests(s, testdata):
    '''封裝requests請求'''
    method = testdata["method"]
    url = testdata["url"]
    # url後面的params參數
    try:
        params = eval(testdata["params"])
    except:
        params = None
    # 請求頭部headers
    try:
        headers = eval(testdata["headers"])
        print("請求頭部:%s" % headers)
    except:
        headers = None
    # post請求body類型
    type = testdata["type"]

    test_nub = testdata['id']
    print("*******正在執行用例:-----  %s  ----**********" % test_nub)
    print("請求方式:%s, 請求url:%s" % (method, url))
    print("請求params:%s" % params)

    # post請求body內容
    try:
        bodydata = eval(testdata["body"])
    except:
        bodydata = {}

    # 判斷傳data數據仍是json
    if type == "data":
        body = bodydata
    elif type == "json":
        body = json.dumps(bodydata)
    else:
        body = bodydata
    if method == "post": print("post請求body類型爲:%s ,body內容爲:%s" % (type, body))

    verify = False
    res = {}   # 接受返回數據

    try:
        r = s.request(method=method,
                      url=url,
                      params=params,
                      headers=headers,
                      data=body,
                      verify=verify
                       )
        print("頁面返回信息:%s" % r.content.decode("utf-8"))
        res['id'] = testdata['id']
        res['rowNum'] = testdata['rowNum']
        res["statuscode"] = str(r.status_code)  # 狀態碼轉成str
        res["text"] = r.content.decode("utf-8")
        res["times"] = str(r.elapsed.total_seconds())   # 接口請求時間轉str
        if res["statuscode"] != "200":
            res["error"] = res["text"]
        else:
            res["error"] = ""
        res["msg"] = ""
        if testdata["checkpoint"] in res["text"]:
            res["result"] = "pass"
            print("用例測試結果:   %s---->%s" % (test_nub, res["result"]))
        else:
            res["result"] = "fail"
        return res
    except Exception as msg:
        res["msg"] = str(msg)
        return res

def wirte_result(result, filename="result.xlsx"):
    # 返回結果的行數row_nub
    row_nub = result['rowNum']
    # 寫入statuscode
    wt = Write_excel(filename)
    wt.write(row_nub, 8, result['statuscode'])       # 寫入返回狀態碼statuscode,第8列
    wt.write(row_nub, 9, result['times'])            # 耗時
    wt.write(row_nub, 10, result['error'])            # 狀態碼非200時的返回信息
    wt.write(row_nub, 12, result['result'])           # 測試結果 pass 仍是fail
    wt.write(row_nub, 13, result['msg'])           # 拋異常

if __name__ == "__main__":
    data = ExcelUtil("debug_api.xlsx").dict_data()
    print(data[0])
    s = requests.session()
    res = send_requests(s, data[0])
    copy_excel("debug_api.xlsx", "result.xlsx")
    wirte_result(res, filename="result.xlsx")

測試用例unittest+ddt

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

# coding:utf-8
import unittest
import ddt
import os
import requests
from excelddtdriver.common import base_api
from excelddtdriver.common import readexcel
from excelddtdriver.common import writeexcel

# 做者:上海-悠悠
# QQ羣:226296743

# 獲取demo_api.xlsx路徑
curpath = os.path.dirname(os.path.realpath(__file__))
testxlsx = os.path.join(curpath, "demo_api.xlsx")

# 複製demo_api.xlsx文件到report下
report_path = os.path.join(os.path.dirname(curpath), "report")
reportxlsx = os.path.join(report_path, "result.xlsx")

testdata = readexcel.ExcelUtil(testxlsx).dict_data()
@ddt.ddt
class Test_api(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.s = requests.session()
        # 若是有登陸的話,就在這裏先登陸了
        writeexcel.copy_excel(testxlsx, reportxlsx) # 複製xlsx

    @ddt.data(*testdata)
    def test_api(self, data):
        # 先複製excel數據到report
        res = base_api.send_requests(self.s, data)

        base_api.wirte_result(res, filename=reportxlsx)
        # 檢查點 checkpoint
        check = data["checkpoint"]
        print("檢查點->:%s"%check)
        # 返回結果
        res_text = res["text"]
        print("返回實際結果->:%s"%res_text)
        # 斷言
        self.assertTrue(check in res_text)

if __name__ == "__main__":
    unittest.main()

生成報告

1.用HTMLTestRunner生成html報告,我這裏改了下名稱,改爲了HTMLTestRunner_api.pypost

# coding=utf-8
import unittest
import time
from excelddtdriver.common import HTMLTestRunner_api
import os

# 做者:上海-悠悠
# QQ羣:226296743

curpath = os.path.dirname(os.path.realpath(__file__))
report_path = os.path.join(curpath, "report")
if not os.path.exists(report_path): os.mkdir(report_path)
case_path = os.path.join(curpath, "case")

def add_case(casepath=case_path, rule="test*.py"):
    '''加載全部的測試用例'''
    # 定義discover方法的參數
    discover = unittest.defaultTestLoader.discover(casepath,
                                                  pattern=rule,)

    return discover

def run_case(all_case, reportpath=report_path):
    '''執行全部的用例, 並把結果寫入測試報告'''
    htmlreport = reportpath+r"\result.html"
    print("測試報告生成地址:%s"% htmlreport)
    fp = open(htmlreport, "wb")
    runner = HTMLTestRunner_api.HTMLTestRunner(stream=fp,
                                               verbosity=2,
                                               title="測試報告",
                                               description="用例執行狀況")

    # 調用add_case函數返回值
    runner.run(all_case)
    fp.close()

if __name__ == "__main__":
    cases = add_case()
    run_case(cases)

2.生成的excel報告

3.生成的html報告

---------------------------------python接口自動化已出書-------------------------
買了此書的小夥伴能夠在書的最後一篇下載到源碼

全書購買地址 https://yuedu.baidu.com/ebook/585ab168302b3169a45177232f60ddccda38e695

---------------------------------python接口自動化完整版-------------------------

全書購買地址 https://yuedu.baidu.com/ebook/585ab168302b3169a45177232f60ddccda38e695

做者:上海-悠悠 QQ交流羣:588402570

也能夠關注下個人我的公衆號:yoyoketang

相關文章
相關標籤/搜索