接口自動化框架pyface詳細介紹

版權說明

本框架系本人結合一些實踐經驗和開源框架設計思想,在家基於興趣愛好獨立完成的代碼開發。html

源碼只保存在私人電腦,辦公電腦上無。github開源與公司無關,先把關係撇清,不涉及侵權。python

噓。mysql

框架定位

首先最重要的就是學習交流,無商業用途。其次本框架有必定實用價值,可做爲工做輔助工具,解決現有技術沒法處理的問題。最後能夠優化改造投入生產實用(如有更好的idea請務必告訴我,求知若渴)。git

設計思想

技術棧

說明文字爲本框架中用途。github

python:腳本語言。sql

requests:http請求庫。數據庫

allure:測試報告json

numpy:數據格式兼容。api

pandas:mysql返回數據處理。瀏覽器

PyMySQL:鏈接mysql。

SQLAlchemy:mysql鏈接引擎,支持ORM。

texttable:日誌打印sql查詢結果表格。

目錄結構

用例組織方式

模板代碼使用code_auto.py自動生成。

self.api_dir = os.path.join(os.path.join(self.base_dir, 'api'), 'bu')  # 1
        self.case_dir = os.path.join(os.path.join(self.base_dir, 'case'), 'sprint')  # 2
        self.uri = '/api/post'  # 3
        self.description = 'Demo auto code'  # 4
        # 5
        self.body = """{}
"""

1 輸入api子目錄名稱。接口是按業務部門來區分的,子目錄名稱建議按業務部門(bu==Business Unit)來設置。

2 輸入測試用例子目錄名稱。如今流行敏捷開發,建議按迭代sprint或獨立功能模塊命名。

3 接口uri。須要注意的是,開頭要有1個斜槓/

4 接口描述。如名稱、做用。

5 請求體。

執行後在api和case目錄生成測試初始化代碼。

域名、Headers/Cookie涉及到環境變量,在data/env設置。

class _GldExp:
    x = 1
    headers = {"Content-Type": "application/json"}
    dao_x = Dao('host:port',
                'username',
                'password')

    test_url = 'https://x'


class _Gld:
    x = 2
    headers = {"Content-Type": "application/json"}
    dao_x = Dao('host:port',
                "username",
                "password")

    test_url = 'https://x'


def uuid_list(n):
    """Uuid list

    @param n: Number
    @return: A uuid list
    """
    return [str(uuid.uuid4()).replace('-', '') for i in range(n)]


# Set environment name
vars_ = _GldExp

2個內部類_GldExp_Gld,定義參數化環境變量。

在env文件中能夠定義一些業務相關函數。公共函數須要放到common/func,建議不要輕易把框架無關的函數放到公共函數裏面。

import env後,使用vars_引用來調用具體的環境變量,如vars_.test_url

測試代碼編寫方式

api/bu目錄下,每一個接口==1個py文件。

class ApiPost(Api):

    def __init__(self):
        super().__init__()
        self.url = vars_.test_url + "/api/post"

    def load(self):
        self.body = {}

        return self

    def send(self):
        self.res = self.req.post(url=self.url, headers=vars_.headers, json=self.body)
        self.set_content()
        return self.res

api繼承了基類Api。根據不一樣環境初始化vars_.test_urlload()方法用於加載參數,send()方法用於發送請求(視不一樣method修改對應的請求方法&參數,如get,能夠在common/request.py中找到相關定義)。

測試代碼徹底面向對象。

def test_default():
    x = ApiPost()
    x.load().send()

這樣能很方便的在接口之間傳遞參數,以及作參數化的工做。

好比,在接口.py中,須要參數化body的name:

def load(self):
        self.body = {
            "name": self.name
        }

PyCharm會提示此屬性未定義,忽略它。

在測試代碼中寫參數化就很簡單:

x.name = 'dongfanger'
    x.load().send()

JMeter參數化方式

本框架參數化借鑑了JMeter的參數化方式。也就是,在接口發請求後,對參數賦值;在接口收到相應後,提取參數。這也是測試代碼要徹底面向對象的緣由。

面向對象能較好的組織測試代碼,使代碼邏輯清晰,閱讀易於理解。

好比,先定義2個接口,蘋果樹和商店:

class AppleTree(Api):

    def __init__(self):
        super().__init__()
        self.url = vars_.test_url + "/api/post/apple/tree"

    def load(self):
        self.body = {}

        return self

    def send(self):
        self.res = self.req.post(url=self.url, headers=vars_.headers, json=self.body)
        self.set_content()
        return self.res
class ShopSale(Api):

    def __init__(self):
        super().__init__()
        self.url = vars_.test_url + "/api/post/shop/sale"

    def load(self):
        self.body = {
            "apple": self.apple
        }

        return self

    def send(self):
        self.res = self.req.post(url=self.url, headers=vars_.headers, json=self.body)
        self.set_content()
        return self.res

測試代碼編寫,蘋果樹先生產蘋果,再運輸到商店,商店賣蘋果:

def test_apple_to_shop():
    apple_tree = AppleTree()
    apple_tree.load().send()  # 生產蘋果
    good_apple = apple_tree.content['good_apple']  # content在Api基類中定義
    shop_sale = ShopSale()
    shop_sale.apple = good_apple  # 傳遞參數
    shop_sale.load().send()
    print(shop_sale.content)

content在Api基類中定義:

def set_content(self):
        """After request, assert status and set content

        """
        status_ok(self.res)
        res_json = self.res.json()
        assert 1000 == res_json.get('status')
        try:
            self.content = res_json['content']
        except KeyError:
            logger.info(f"{'*' * 26}\n"
                        f"Response no content\n"
                        f"{'*' * 26}\n")

先斷言返回狀態ok,再取響應json裏面key爲content的value。不一樣公司json規範不同,須要作調整。

批量執行用例生成測試報告

pytest_allure.py批量執行測試用例。

# Input the directory to run pytest
run_dir = os.path.join(base_dir, 'case')

默認執行case目錄下test_開頭或結尾的文件(pytest規則)。測試方法須要以test_開頭。

能夠指定目錄,如:

# Input the directory to run pytest
run_dir = os.path.join(os.path.join(base_dir, 'case'), 'sprint0001')

本框架藉助pytest_sessionfinish hook函數實現了生成測試報告並自動打開瀏覽器。

def pytest_sessionfinish(session):
    allure_report_dir_test = session.config.getoption('allure_report_dir')
    if allure_report_dir_test:
        html_dir = os.path.join(allure_report_dir_test, 'html')
        os.system(f'mkdir {html_dir}')
        os.system(f"allure generate {allure_report_dir_test} -o {html_dir}")
        os.system(f"allure open {html_dir}")

mysql支持

mysql主要用於:一提供參數化賦值;二數據庫比對斷言。

commons/dao.py實現了相關功能。在data/env.py中根據環境定義好鏈接後,經過vars_使用。

dao_x = Dao('host:port',
                'username',
                'password')
sql_result = vars_.dao_x.select('select id, name from new_table;')

dao實現採用了pandas+sqlalchemy,對返回結果取值就能夠按dataframe來,如sql_result['name'][0]

藉助texttable會打印表格日誌,觀察數據。

[2020-03-22 18:14:13]Running sql
select id, name from new_table;

[2020-03-22 18:14:14]Sql result:
+----+------+
| id | name |
+====+======+
| 1  | w    |
+----+------+
| 2  | g    |
+----+------+

值得說明的是,爲了數據校驗方便,默認會把無小數的float轉換爲int,如5.0->5

@staticmethod
    def _convert(x):
        """Convert logic code

        @param x: Single cell data
        @return: Converted single cell data
        """
        # float to int
        if isinstance(x, float) and x % 1 == 0:
            return int(x)
        return x

結語

開源使我快樂。

分享才能收穫更多。

我在github等你。

https://github.com/dongfanger/pyface
版權申明:本文爲博主原創文章,轉載請保留原文連接及做者。

相關文章
相關標籤/搜索