Python Api接口自動(dòng)化測(cè)試框架 excel篇

很多人希望開源源碼, github上源碼:https://github.com/F1And/api4excel
喜歡給個(gè)star。

工作原理: 測(cè)試用例在excel上編輯,使用第三方庫xlrd,讀取表格sheet和內(nèi)容,sheetName對(duì)應(yīng)模塊名,Jenkins集成服務(wù)發(fā)現(xiàn)服務(wù)moduleName查找對(duì)應(yīng)表單,運(yùn)用第三方庫requests請(qǐng)求接口,根據(jù)結(jié)果和期望值進(jìn)行斷言,根據(jù)輸出報(bào)告判斷接口測(cè)試是否通過。
1. 數(shù)據(jù)準(zhǔn)備
  • 數(shù)據(jù)插入(容易實(shí)現(xiàn)的測(cè)試場(chǎng)景下所需外部數(shù)據(jù))
  • 準(zhǔn)備sql (接口需要重復(fù)使用,參數(shù)一定得是變量)
2.集成部署(運(yùn)維相關(guān)了解即可)
  • 平滑升級(jí)驗(yàn)證腳本加入自動(dòng)化
3.自動(dòng)化框架實(shí)現(xiàn)
  • 調(diào)用mysql
  • excel遍歷測(cè)試用例
  • requests實(shí)現(xiàn)接口調(diào)用
  • 根據(jù)接口返回的code值和Excel對(duì)比
  • 報(bào)告反饋
  • 暴露服務(wù)

寫一個(gè)簡(jiǎn)單登錄的接口自動(dòng)化測(cè)試

代碼的分層如下圖:
代碼結(jié)構(gòu)

一、寫一個(gè)封裝的獲取excel表格的模塊

excel.png

代碼實(shí)現(xiàn)如下:

 # !/usr/bin/python
 # -*- coding: UTF-8 -*-
 # author: 赫本z
 # 基礎(chǔ)包: 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):
    """
    獲取行號(hào)
    :param sheet: sheet
    :return: 行數(shù)
    """
    return sheet.nrows

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

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

代碼封裝后當(dāng)成模塊引用,這還是最開始呢。

二、引用log模塊獲取日志

準(zhǔn)備工作:
需要一個(gè)日志的捕獲,包括框架和源碼拋出的expection。
代碼如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# author: 赫本z
# 基礎(chǔ)包: 日志服務(wù)
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模塊接口測(cè)試

準(zhǔn)備工作:
需要的請(qǐng)求類型和執(zhí)行測(cè)試的方法。絕大多數(shù)公司使用Post和Get請(qǐng)求,一部分公司還在使用Restful API設(shè)計(jì)方案,可以因材施教。
代碼如下:

#!/usr/bin/python
#-*- coding: UTF-8 -*-
# 基礎(chǔ)包:接口測(cè)試的封裝

import requests
import core.log as log
import json

logging = log.get_logger()

def change_type(value):
    """
    對(duì)dict類型進(jìn)行中文識(shí)別
    :param value: 傳的數(shù)據(jù)值
    :return: 轉(zhuǎn)碼后的值
    """
    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):
    """
    自定義一個(gè)接口測(cè)試的方法
    :param method: 請(qǐng)求類型
    :param url: 地址
    :param data: 數(shù)據(jù)
    :param headers: 請(qǐng)求頭
    :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):
    """
    請(qǐng)求response自己可以自定義檢查結(jié)果
    :param method: 請(qǐng)求類型
    :param url: 請(qǐng)求地址
    :param data: 請(qǐng)求參數(shù)
    :param headers: 請(qǐng)求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("請(qǐng)求失敗 %s" % e)

四、關(guān)于function模塊

主要調(diào)用二次封裝的代碼,結(jié)合業(yè)務(wù)做一個(gè)通用代碼。如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 業(yè)務(wù)包:通用函數(shù)


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:
    """接口測(cè)試業(yè)務(wù)類"""
    filename = cs.FILE_NAME

    def __init__(self):
        pass

    def prepare_data(self, host, user, password, db, sql):
        """數(shù)據(jù)準(zhǔn)備,添加測(cè)試數(shù)據(jù)"""
        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):
        """依據(jù)模塊名獲取sheet"""
        excel.open_excel(path)
        return excel.get_sheet(module)

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

    def run_test(self, sheet, url):
        """再執(zhí)行測(cè)試用例"""
        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

五、關(guān)于參數(shù)中constans模塊

準(zhǔn)備工作:
所有的參數(shù)和常量我們會(huì)整理到這個(gè)文件中,因?yàn)樵O(shè)計(jì)業(yè)務(wù)和服務(wù)密碼、數(shù)據(jù)庫密碼這里展示一部分。
代碼如下:

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

CASE_NUMBER = 0  # 用例編號(hào)
CASE_NAME = 1    # 用例名稱
CASE_DATA = 2    # 用例參數(shù)
CASE_URL = 3     # 用例接口地址
CASE_METHOD = 4  # 用例請(qǐng)求類型
CASE_CODE = 5    # 用例code
CASE_HEADERS = 6 # 用例headers

SQL_ROW = 0      # 預(yù)執(zhí)行SQL的行號(hào)
SQL_COL = 1      # 預(yù)執(zhí)行SQL的列號(hào)

FILE_NAME = 'test.xlsx'

六、寫一個(gè)run文件:只是用來執(zhí)行的,業(yè)務(wù)和代碼剝離。

代碼如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 驗(yàn)證包:接口測(cè)試腳本

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

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

"""1.外部輸入?yún)?shù)"""

module = 'user'
url = 'http://127.0.0.1:8080'

"""2.根據(jù)module獲取Sheet"""
logging.info("-------------- Execute TestCases ---------------")
sheet = func.get_excel_sheet(func.filename,  module)

# """3.數(shù)據(jù)準(zhǔn)備"""
# 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.執(zhí)行測(cè)試用例"""
res = func.run_test(sheet, url)
logging.info("-------------- Get the result ------------ %s", res)

七、查看測(cè)試報(bào)告(部署到j(luò)enkins會(huì)通過控制臺(tái)查看)

報(bào)告.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容