天天看點

通用 api 封裝實戰,帶你深入了解 PO

通用 api 封裝實戰,帶你深入了解 PO

在普通的接口自動化測試中,如果接口的參數,比如 url,headers等傳參改變,或者測試用例的邏輯、斷言改變,那麼整個測試代碼都需要改變。apiobject設計模式借鑒了pageobject的設計模式,可以實作一個優雅、強大的接口測試架構。

理念

apiobject設計模式可以簡單分為6個子產品,分别是API對象、接口測試架構、配置子產品、資料封裝、Utils、測試用例。

  • 接口測試架構:base_api,完成對api的驅動
  • API對象:繼承base_api後,完成對接口的封裝
  • 配置子產品:完成配置檔案的讀取
  • 資料封裝:資料構造與測試用例的資料封裝
  • Utils:其他功能封裝,改進原生架構不足
  • 測試用例:調用Page/API對象實作業務并斷言

枯燥的講述概念可能難以了解,後面的章節都會圍繞這些子產品進行理論的拆解和執行個體的示範。

api 模式應用

在這裡将會結合企業微信的部門管理,擷取部門清單接口作為一個接口測試用例,從沒有封裝到使用apiobject設計模式進行封裝改造。将實戰與理論結合,更深入了解apiobject設計模式。

環境準備

企業微信服務端API:接口文檔 - 企業微信開發者中心

import requests

class TestDemo:

    def test_get_token(self):

        r = requests.get(url="https://qyapi.weixin.qq.com/cgi-bin/gettoken",

            params={"corpid": "ww93348658d7c66ef4", "corpsecret": "T0TFrXmGYel167lnkzEydsjl6bcDDeXVmkUnEYugKIw"})

        return r.json()["access_token"]

    def test_department_list(self):

        r = requests.get(url="https://qyapi.weixin.qq.com/cgi-bin/department/list",

            params={"access_token": self.test_get_token(), "id": 1})

        assert r.json()["errcode"] == 0

        return print(r.json())           

思路

  • api
    • base_api.py是用來封裝所有api的通用方法,比如列印log、對斷言工具做二次封裝等,不牽涉和業務相關的操作
    • wework.py繼承base_api并實作基本業務,之後所有的具體的業務資源繼承自wework,比如token的擷取等;
    • department繼承自wework,用來實作對應子產品具體的業務邏輯,比如發送請求,請求内有什麼參數等等。
  • testcases檔案夾内統一存放所有的測試用例,調用API對象實作業務并斷言
  • utils檔案夾記憶體放對其他功能封裝,改進原生架構不足
  • data檔案夾資料構造與測試用例的資料封裝此外,還有配置子產品與資料封裝會在後面的章節進行具體的介紹
通用 api 封裝實戰,帶你深入了解 PO

實戰案例

utils.py,在此檔案中封裝一個jsonpath方法。

import json

from jsonpath import jsonpath

class Utils:

    @classmethod

    def jsonpath(cls, json_object, expr):

        return jsonpath(json_object, expr)           

base_api.py,在此檔案中調用utils中的jsonpath方法。

from test_wework.utils.Utils import Utils

class BaseApi:

    json_data = None

    def jsonpath(self, expr):

        return Utils.jsonpath(self.json_data, expr)           

wework.py,繼承類BaseApi,實作token的擷取。将在後面“通用api封裝”章節中詳細講述函數内部的設計。

class WeWork(BaseApi):

    corpid = "ww93348658d7c66ef4"

    contact_secret = "T0TFrXmGYel167lnkzEydsjl6bcDDeXVmkUnEYugKIw"

    token = dict()

    token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"

    @classmethod

    def get_token(cls, secret=contact_secret):

        # 避免重複請求,提高速度

        if secret not in cls.token.keys():

            r = cls.get_access_token(secret)

            cls.token[secret] = r["access_token"]

        return cls.token[secret]

    @classmethod

    def get_access_token(cls, secret):

        r = requests.get(cls.token_url, params={"corpid": cls.corpid, "corpsecret": secret})

        return r.json()           

department.py,繼承類WeWork,發起一個get請求,擷取department的list。

class Department(BaseApi):

    list_url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"

    def list(self, id):

        self.json_data = requests.get(self.list_url, params={"access_token": WeWork.get_contact_token(), "id": id}).json()

        return self.json_data           

test_department.py,斷言傳回值中的第一個name是否為“WestWayyt”。

class TestDepartment:

    department = Department()

    def test_department_list(self):

        r = self.department.list(1)

        assert self.department.jsonpath(expr="$..name")[0] == "WestWayyt"           

通用 api 封裝實戰

在apiobject設計模式中,需要一個“base_api”作為其他api步驟的父類,把通用功能放在這個父類中,供其他的api直接繼承調用。這樣做的優點在于,減少重複代碼,提高代碼的複用性。

上文在示範使用api-object設計模式對腳本進行改造時提到了base_api。不過在上文,僅僅隻是封裝了一個utils中的一個簡單方法。并沒有完全展現出base_api的實際作用。

接下來會通過通用接口協定的定義與封裝實戰,實際體會一下base_api的巧妙之處。

base_api.py,在代碼内,對request進行一層封裝,當然在這裡還看不出來具體的優勢:

import requests

class BaseApi:

    def request(self, method, url, **kwargs):

        self.json_data = requests.request(method=method, url=url, **kwargs)

        return self.json_data           

wework.py,繼承于類BaseApi,可以直接調用父類中的request方法(不需要導入requests庫),進而發起一個get請求:

from test_interface.test_wework.api.base_api import BaseApi

class WeWork(BaseApi):

    corpid = "ww93348658d7c66ef4"

    contact_secret = "T0TFrXmGYel167lnkzEydsjl6bcDDeXVmkUnEYugKIw"

    token = dict()

    token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"

    def get_access_token(self):

        r = self.request(method="get", url=self.token_url,

                         params={"corpid": self.corpid, "corpsecret": self.contact_secret})

        return r.json()           

test_wework.py,繼承于類WeWork,主要目的隻是為了檢查上面的get_access_token(self) 是否成功:

from test_interface.test_wework.api.wework import WeWork

class TestWeWork(WeWork):

    def test_get_access_token(self):

        r = self.get_access_token()

        assert r["errcode"]==0           

在上面的案例中,在base_api.py中對 requests 進行了多一層的封裝,這樣子,隻要是屬于BaseApi這個類的子類,都可以無需引用而直接調用 requests 庫。進而發起各種各樣的請求,實作了通用接口協定的定義與封裝。

搜尋微信公衆号:TestingStudio 霍格沃茲的幹貨都很硬核

繼續閱讀