前言
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新手可能遇到模塊導入報錯問題
- 局限性太多,所以已經棄用!!謹慎入坑,換pytest框架了
項目結構
excel測試數據
xlrd讀excel數據
1.先從excel里面讀取測試數據,返回字典格式
# 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數據的方法
# 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請求方法,傳入請求參數,並返回結果
2.為了不污染測試的數據,出報告的時候先將測試的excel復制都應該新的excel
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.py
# 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