1. 程式人生 > >api4excel - 接口自動化測試excel篇

api4excel - 接口自動化測試excel篇

canonical num 平滑 lob highlight RM tar 結果 識別

api4excel - 接口自動化測試excel篇

工作原理: 測試用例在excel上編輯,使用第三方庫xlrd,讀取表格sheet和內容,sheetName對應模塊名,Jenkins集成服務發現服務moduleName查找對應表單,運用第三方庫requests請求接口,根據結果和期望值進行斷言,根據輸出報告判斷接口測試是否通過。

1. 數據準備
  • 數據插入(容易實現的測試場景下所需外部數據)
  • 準備sql (接口需要重復使用,參數一定得是變量)
2.集成部署(運維相關了解即可)
  • 平滑升級驗證腳本加入自動化
3.自動化框架實現
  • 調用mysql
  • excel遍歷測試用例
  • requests實現接口調用
  • 根據接口返回的code值和Excel對比
  • 報告反饋
  • 暴露服務

寫一個簡單登錄的接口自動化測試

代碼的分層如下圖:

技術分享圖片

一、寫一個封裝的獲取excel表格的模塊

技術分享圖片

代碼實現如下:

 # !/usr/bin/python
 # -*- coding: UTF-8 -*-
 # author: 赫本z
 # 基礎包: excel的封裝

import xlrd
workbook = None

def open_excel(path):
     """
     打開excel
     :param path: 打開excel文件的位置
     """
     global workbook
     if (workbook == None):
        workbook = xlrd.open_workbook(path, on_demand=True)

def get_sheet(sheetName):
     """
     獲取頁名
     :param sheetName: 頁名
     :return: workbook
     """
     global workbook
     return workbook.sheet_by_name(sheetName)

def get_rows(sheet):
    """
    獲取行號
    :param sheet: sheet
    :return: 行數
    """
    return sheet.nrows

def get_content(sheet, row, col):
    """
    獲取表格中內容
    :param sheet: sheet
    :param row: 行
    :param col: 列
    :return:
    """
    return sheet.cell(row, col).value

def release(path):
    """釋放excel減少內存"""
    global workbook
    workbook.release_resources()
    del workbook
    # todo:沒有驗證是否可用

代碼封裝後當成模塊引用,這還是最開始呢。

二、引用log模塊獲取日誌

準備工作: 需要一個日誌的捕獲,包括框架和源碼拋出的expection。 代碼如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# author: 赫本z
# 基礎包: 日誌服務
import logging

def get_logger():
    global logPath
    try:
        logPath
    except NameError:
        logPath = ""
    FORMAT = %(asctime)s - %(name)s - %(levelname)s - %(message)s‘
    logging.basicConfig(level=logging.INFO, format=FORMAT)
    return logging

三、引用requests模塊接口測試

準備工作: 需要的請求類型和執行測試的方法。 代碼如下:

#!/usr/bin/python
#-*- coding: UTF-8 -*-
# 基礎包:接口測試的封裝

import requests
import core.log as log
import json

logging = log.get_logger()

def change_type(value):
    """
    對dict類型進行中文識別
    :param value: 傳的數據值
    :return: 轉碼後的值
    """
    try:
        if isinstance(eval(value), str):
            return value
        if isinstance(eval(value), dict):
            result = eval(json.dumps(value))
            return result
    except Exception, e:
        logging.error("類型問題 %s", e)


def api(method, url, data ,headers):
    """
    自定義一個接口測試的方法
    :param method: 請求類型
    :param url: 地址
    :param data: 數據
    :param headers: 請求頭
    :return: code碼
    """
    global results
    try:
        if method == ("post" or "POST"):
            results = requests.post(url, data, headers=headers)
        if method == ("get" or "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)


def content(method, url, data, headers):
    """
    請求response自己可以自定義檢查結果
    :param method: 請求類型
    :param url: 請求地址
    :param data: 請求參數
    :param headers: 請求headers
    :return: message信息
    """
    global results
    try:
        if method == ("post" or "POST"):
            results = requests.post(url, data, headers=headers)
        if method == ("get" or "GET"):
            results = requests.get(url, data, headers=headers)
        if method == ("put" or "PUT"):
            results = requests.put(url, data, headers=headers)
        if method == ("patch" or "PATCH"):
            results = requests.patch(url, data, headers=headers)
        response = results.json()
        message = response.get("message")
        result = response.get("result")
        content = {"message": message, "result": result}
        return content
    except Exception, e:
        logging.error("請求失敗 %s" % e)

四、關於function模塊

主要調用二次封裝的代碼,結合業務做一個通用代碼。如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 業務包:通用函數


import core.mysql as mysql
import core.log as log
import core.request as request
import core.excel as excel
import constants as cs
from prettytable import PrettyTable

logging = log.get_logger()


class ApiTest:
    """接口測試業務類"""
    filename = cs.FILE_NAME

    def __init__(self):
        pass

    def prepare_data(self, 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(self, path, module):
        """依據模塊名獲取sheet"""
        excel.open_excel(path)
        return excel.get_sheet(module)

    def get_prepare_sql(self, sheet):
        """獲取預執行SQL"""
        return excel.get_content(sheet, cs.SQL_ROW, cs.SQL_COL)

    def run_test(self, sheet, url):
        """再執行測試用例"""
        rows = excel.get_rows(sheet)
        fail = 0
        for i in range(2, rows):
            testNumber = str(int(excel.get_content(sheet, i, cs.CASE_NUMBER)))
            testData = excel.get_content(sheet, i, cs.CASE_DATA)
            testName = excel.get_content(sheet, i, cs.CASE_NAME)
            testUrl = excel.get_content(sheet, i, cs.CASE_URL)
            testUrl = url + testUrl
            testMethod = excel.get_content(sheet, i, cs.CASE_METHOD)
            testHeaders = eval(excel.get_content(sheet, i, cs.CASE_HEADERS))
            testCode = excel.get_content(sheet, i, cs.CASE_CODE)
            actualCode = request.api(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

五、關於參數中constans模塊

準備工作: 所有的參數和常量我們會整理到這個文件中,因為設計業務和服務密碼、數據庫密碼這裏展示一部分。 代碼如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 通用包:常量

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的列號

FILE_NAME = ‘test.xlsx

六、寫一個run文件:只是用來執行的,業務和代碼剝離。

代碼如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 驗證包:接口測試腳本

import core.log as log
from function.func import ApiTest

func = ApiTest()
logging = log.get_logger()

"""1.外部輸入參數"""

module = ‘user‘
url = ‘http://127.0.0.1:8080"""2.根據module獲取Sheet"""
logging.info("-------------- Execute TestCases ---------------")
sheet = func.get_excel_sheet(func.filename,  module)

# """3.數據準備"""
# logging.info("-------------- Prepare data through MysqlDB --------------")
# sql = func.get_prepare_sql(sheet)
# func.prepare_data(host=host, user=user, password=password, db=db, sql=sql)

"""4.執行測試用例"""
res = func.run_test(sheet, url)
logging.info("-------------- Get the result ------------ %s", res)

七、查看測試報告(部署到jenkins會通過控制臺查看)

技術分享圖片

api4excel - 接口自動化測試excel篇