公司內部的一個接口自動化使用框架(非使用工具)
工作原理: 測試用例在excel上編輯,使用第三方庫xlrd,讀取表格sheet和內容,sheetName對應模塊名,Jenkins集成服務發現服務moduleName查找對應表單,運用第三方庫requests請求接口,根據結果和期望值進行斷言,根據輸出報告判斷接口測試是否通過。
1. 數據準備
數據插入(容易實現的測試場景下所需外部數據)
準備sql (接口需要重複使用,參數一定得是變量)
2.集成部署(運維相關了解即可)
平滑升級驗證腳本加入自動化
3.自動化框架實現
●調用mysql
●excel遍歷測試用例
●requests實現接口調用
●根據接口返回的code值和Excel對比
●報告反饋
●暴露服務
寫一個簡單登錄的接口自動化測試
代碼的分層如下圖:
coding.png
一、寫一個封裝的獲取excel表格的模塊
excel.png
代碼實現如下:
# !/usr/bin/python # -*- coding: UTF-8 -*- # 基礎包:excel的封裝 import xlrd workbook = None def open_excel(path): """打開excel""" global workbook if (workbook == None): workbook = xlrd.open_workbook(path, on_demand=True) def get_sheet(sheetName): """獲取頁名""" global workbook return workbook.sheet_by_name(sheetName) def get_rows(sheet): """獲取行號""" return sheet.nrows def get_content(sheet, row, col): """獲取表格中內容""" return sheet.cell(row, col).value def release(path): """釋放excel減少內存""" global workbook workbook.release_resources() del workbook |
代碼封裝後當成模塊引用,這還是最開始呢。
二、引用log模塊獲取日誌
準備工作:
需要一個日誌的捕獲,包括框架和源碼拋出的expection。
代碼如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 基礎包:日誌服務 import logging import time def getLogger(): global tezLogPath try: tezLogPath except NameError: tezLogPath = "/data/log/apiTest/" FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' # file = tezLogPath + time.strftime("%Y-%m-%d", time.localtime()) + ".log" # logging.basicConfig(filename=file, level=logging.INFO, format=FORMAT) # 開發階段爲了方便調試,可不輸出到文件 logging.basicConfig(level=logging.INFO, format=FORMAT) return logging |
三、引用requests模塊接口測試
準備工作:
需要的請求類型和執行測試的方法。
代碼如下:
#!/usr/bin/python# #-*- coding: UTF-8 -*- # 基礎包:接口測試的封裝 import requests import tezLog as log logging = log.getLogger() def api_test(method, url, data ,headers): """ 定義一個請求接口的方法和需要的參數 :Args: method - 企業名稱 str url - 用戶暱稱 str data - 參數 str headers - 請求頭信息 dict 非RESTful API請求另外的請求類型實際用不到。也不安全。 """ try: if method == "post": results = requests.post(url, data, headers=headers) if method == "get": results = requests.get(url, data, headers=headers) # if method == "put": # results = requests.put(url, data, headers=headers) # if method == "delete": # results = requests.delete(url, headers=headers) # if method == "patch": # results == requests.patch(url, data, headers=headers) # if method == "options": # results == requests.options(url, headers=headers) response = results.json() code = response.get("code") return code except Exception, e: logging.error("service is error", e) |
四、關於common模塊
主要調用二次封裝的代碼,結合業務做一個通用代碼。如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 業務包:通用函數 import core.tezMysql as mysql import core.tezLog as log import gl import core.tezExcel as excel import core.tezRequest as request from prettytable import PrettyTable filename = gl.FILE_NAME logging = log.get_logger() def prepare_data(host, user, password, db, sql): """數據準備,添加測試數據""" mysql.connect(host, user, password, db) res = mysql.execute(sql) mysql.close() logging.info("Run sql: the row number affected is %s", res) return res def get_excel_sheet(path, module): """依據模塊名獲取sheet""" excel.open_excel(path) return excel.get_sheet(module) def replace_holder(value): """遍歷字典替換佔位符""" for holder in gl.PLACE_HOLDER: value = value.replace(holder, gl.PLACE_HOLDER[holder]) return value def get_prepare_sql(sheet): """獲取預執行SQL""" return replace_holder(excel.get_content(sheet, gl.SQL_ROW, gl.SQL_COL)) def run_test(sheet, url): """再執行測試用例""" rows = excel.get_rows(sheet) fail = 0 for i in range(2, rows): testNumber = str(int(excel.get_content(sheet, i, gl.CASE_NUMBER))) testData = excel.get_content(sheet, i, gl.CASE_DATA) testName = excel.get_content(sheet, i, gl.CASE_NAME) testUrl = excel.get_content(sheet, i, gl.CASE_URL) testUrl = url + testUrl testMethod = excel.get_content(sheet, i, gl.CASE_METHOD) testHeaders = str(excel.get_content(sheet, i, gl.CASE_HEADERS)) testHeaders = eval(replace_holder(testHeaders)) testCode = excel.get_content(sheet, i, gl.CASE_CODE) actualCode = request.api_test(testMethod, testUrl, testData, testHeaders) expectCode = str(int(testCode)) failResults = PrettyTable(["Number", "Method", "Url", "Data", "ActualCode", "ExpectCode"]) failResults.align["Number"] = "l" failResults.padding_width = 1 failResults.add_row([testNumber, testMethod, testUrl, testData, actualCode, expectCode]) if actualCode != expectCode: logging.info("FailCase %s", testName) print "FailureInfo" print failResults fail += 1 else: logging.info("Number %s", testNumber) logging.info("TrueCase %s", testName) if fail > 0: return False return True |
五、關於參數中gl模塊
準備工作:
所有的參數和常量我們會整理到這個文件中,因爲設計業務和服務密碼、數據庫密碼這裏展示一部分。
代碼如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 腳本功能:全部變量 import time import uuid CASE_NUMBER = 0 # 用例編號 CASE_NAME = 1 # 用例名稱 CASE_DATA = 2 # 用例參數 CASE_URL = 3 # 用例接口地址 CASE_METHOD = 4 # 用例請求類型 CASE_CODE = 5 # 用例code CASE_HEADERS = 6 # 用例headers SQL_ROW = 0 # 預執行SQL的行號 SQL_COL = 1 # 預執行SQL的列號 |
六、寫一個run文件:只是用來執行的,業務和代碼剝離。
代碼如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 驗證包:接口測試腳本 import sys import core.tezLog as log import function.common as common logging = log.getLogger() """1.外部輸入參數""" path = sys.path[0] # 當前路徑 module = sys.argv[1] # 服務模塊名 url = sys.argv[2] # 服務地址 host = sys.argv[3] # 數據庫地址 user = sys.argv[4] # 數據庫用戶名 password = sys.argv[5] # 數據庫密碼 db = sys.argv[6] # 數據庫名稱 """2.根據module獲取Sheet""" logging.info("-------------- Execute TestCases ---------------") sheet = common.get_excel_sheet(path + "/" + common.filename, module) """3.數據準備""" logging.info("-------------- Prepare data through MysqlDB --------------") sql = common.get_prepare_sql(sheet) common.prepare_data(host=host, user=user, password=password, db=db, sql=sql) """4.執行測試用例""" res = common.run(sheet, url) logging.info("-------------- Get the result ------------ %s", res) """這裏的res是我們平滑升級的時候需要返回結果爲TRUE纔會繼續下面走。""" |