1. 程式人生 > 其它 >通用 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:https://work.weixin.qq.com/api/doc/90000/90135/90664。不加任何封裝和改造的企業微信,獲取部門列表介面測試用例


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資料夾資料構造與測試用例的資料封裝此外,還有配置模組與資料封裝會在後面的章節進行具體的介紹

** 實戰案例**

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


import jsonfrom 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 庫。從而發起各種各樣的請求,實現了通用介面協議的定義與封裝。

** _
來霍格沃茲測試開發學社,學習更多軟體測試與測試開發的進階技術,知識點涵蓋web自動化測試 app自動化測試、介面自動化測試、測試框架、效能測試、安全測試、持續整合/持續交付/DevOps,測試左移、測試右移、精準測試、測試平臺開發、測試管理等內容,課程技術涵蓋bash、pytest、junit、selenium、appium、postman、requests、httprunner、jmeter、jenkins、docker、k8s、elk、sonarqube、jacoco、jvm-sandbox等相關技術,全面提升測試開發工程師的技術實力

點選獲取更多資訊