tep使用者手冊幫你從unittest過渡到pytest

dongfanger發表於2020-12-23

unittest和pytest是Python的2個強大的測試框架,經常用來做UI自動化或介面自動化。unittest是PyCharm的預設整合工具,也是我們大多數人入門自動化的首選框架。pytest提供了更豐富的功能,相對的上手難度也要高一點。如果學了pytest後,想快速用pytest寫專案,用於工作實踐,那麼可以試試我寫的這款測試工具:tep,try easy pytest。

tep簡介

在Google中輸入python tep

tep使用者手冊幫你從unittest過渡到pytest

tep是一款測試工具,不是測試框架,它做的事情只是幫助你更輕鬆的使用pytest寫專案程式碼,主要功能如下:

  • 專案腳手架
  • pytest用例組織
  • 輸出HTML測試報告
  • 基於fixture管理環境變數
  • 基於fixture共享公共函式
  • 訪問MySQL資料庫
  • 整合常用第三方包
  • 登入介面示例程式碼

工具安裝

安裝

tep已經上傳到了PyPI(Python Package Index):

tep使用者手冊幫你從unittest過渡到pytest

可以使用pip命令安裝:

pip install tep

外網速度慢,pandas可能安裝失敗,推薦用國內映象:

pip --default-timeout=6000 install -i https://pypi.tuna.tsinghua.edu.cn/simple tep

由於整合了第三方包,安裝可能會花幾分鐘,請耐心等待。

Python版本 3.6+

檢查

安裝完成後,檢查是否安裝成功:

tep -V
0.5.3

或者:

tep --version
0.5.3

升級

使用-U引數:

pip install -U tep

或者指定版本:

pip install tep==0.5.3

快速建立專案

tep提供了腳手架,預置了專案結構和程式碼,開啟cmd,使用startproject命令快速建立專案:

cd some_directory
tep startproject project_name
startproject

建立後的專案結果如下:

tep使用者手冊幫你從unittest過渡到pytest

當前版本主要用來做介面自動化,建議把不同業務系統建成多個專案。

1個檔案2處修改完成登入請求

tep已經預置了登入相關程式碼,只需要開啟fixtures\fixture_admin.py,修改2個地方的程式碼,就可以完成登入請求。

修改環境變數

編輯fixtures/fixture_admin.py

@pytest.fixture(scope="session")
def env_vars(config):
    class Clazz:
        def __init__(self):
            env = config["env"]
            self.mapping = {
                "qa": {
                    "domain": "https://qa.com",
                    "mysql_engine": mysql_engine("127.0.0.1",  # host
                                                 "2306",  # port
                                                 "root",  # username
                                                 "123456",  # password
                                                 "test")  # db_name
                },
                "release": {
                    "domain": "https://release.com",
                    "mysql_engine": mysql_engine("127.0.0.1",
                                                 "2306",
                                                 "root",
                                                 "123456",
                                                 "release")
                }
                # Add your env and variables
            }
            self.domain = self.mapping[env]["domain"]
            self.mysql_engine = self.mapping[env]["mysql_engine"]
            # Add properties

        def add(self, env, key, value):
            self.mapping[config["env"]][key] = value

    return Clazz()

mapping是個字典,預置了2個環境:qarelease,每個環境預置了2個變數:domainmysql_engine

domain

url = domain +uri,例如https://qa.com/api/users/login/的domain是``https://qa.com,uri是/api/users/login/`。

首先把qa環境的domain值改為你的測試域名。

修改登入程式碼

繼續編輯fixtures/fixture_admin.py

def _jwt_headers(token):
    return {"Content-Type": "application/json", "authorization": f"Bearer {token}"}


@pytest.fixture(scope="session")
def login():
    # Code your login
    logger.info("Administrator login")
    response = request(
        "post",
        url=url("/api/users/login/"),
        headers={"Content-Type": "application/json"},
        json={
            "username": "admin",
            "password": "123456",
        }
    )
    assert response.status_code < 400
    response_token = jmespath.search("token", response.json())

    class Clazz:
        token = response_token
        jwt_headers = _jwt_headers(response_token)

    return Clazz

# Code your login處開始修改程式碼,替換API路徑/api/users/login/和請求引數json。如果你的登入介面不會返回token,那麼修改jmespath.search("token", response.json())為實際響應取值。

tep預置登入返回了2個值:tokenjwt_headers

測試登入

開啟tests/login_test.py

from loguru import logger


def test_login(login):
    logger.info(login.token)

執行後就會呼叫登入介面發起請求。

遇到問題無法解決請留言或加群。

編寫測試用例

用例組織

測試用例全部放在tests目錄下:

tep使用者手冊幫你從unittest過渡到pytest

每個.py模組以test_字首或_test字尾命名,每個test函式以test字首命名。只要遵循這個規則,目錄層次不影響。示例:

tep使用者手冊幫你從unittest過渡到pytest

建議每個.py模組只包含1個test函式,也就是1條測試用例。

介面請求設計

每條測試用例可以包含單個或多個介面請求。tep預置了1個POST請求示例程式碼,開啟tests/post_test.py

import jmespath
from loguru import logger

from tep.client import request


def test_post(faker_ch, url, login):
    # description
    logger.info("test post")
    # data
    fake = faker_ch
    # request
    response = request(
        "post",
        url=url("/api/users"),
        headers=login.jwt_headers,
        json={
            "name": fake.name()
        }
    )
    # assert
    assert response.status_code < 400
    # extract
    user_id = jmespath.search("id", response.json())

每個請求由5部分組成,從上往下分別是描述、資料、請求、斷言和提取。

借鑑了JMeter元件和引數化關聯的設計思想。

描述

描述這個請求是幹嘛的。

資料

初始化區域性變數,例如使用faker庫造測試資料。

請求

如果需要列印請求日誌,可以from tep.client import requesttep.client.requestrequests.request除了記錄日誌外,沒有做任何修改。

如果請求報錯了,那麼很可能是程式碼寫錯了。

也可以直接使用原生requestfrom requests import request

不同請求方法的程式碼如下:

request("get", url="", headers={}, json={})
request("post", url="", headers={}, params={})
request("put", url="", headers={}, json={})
request("delete", url="", headers={})

# 上傳excel
request("post",
        url="",
        headers={},
        files={
            "file": (
                file_name,
                open(file_path, "rb"),
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            )
        },
        verify=False
    )

更多用法參考requests.request

斷言

斷言使用Python標準斷言assert 表示式,表示式跟if語句表示式一模一樣。

提取

推薦使用jmespath提取JSON資料,也可以使用Python[]中括號提取。

HTML測試報告

批量執行用例

單個測試用例,在PyCharm中執行就可以了。多個測試用例批量執行,需要開啟左下角的Terminal,輸入命令來執行:

# 先進入tests目錄
cd tests
# 批量執行
pytest

只收集不執行

如果只想統計用例條數,不執行程式碼,那麼可以使用以下命令:

pytest --co

HTML測試報告

tep提供了--tep-reports引數來生成allure測試報告:

pytest  --tep-reports

報告檔案存放在根目錄的reports/中:

tep使用者手冊幫你從unittest過渡到pytest

右鍵index.html選擇:

tep使用者手冊幫你從unittest過渡到pytest

就會開啟瀏覽器顯示測試報告了:

image-20201222172647121

預設allure報告右上角的TREND是無法顯示資料的,--tep-reports修復了這個問題,根據history資料生成TREND走勢圖。

自定義環境變數

靜態新增

編輯fixtures/fixture_admin.py,在mapping字典中# Add your env and variables處新增環境變數,在# Add properties處新增屬性,參考domainmysql_engine。示例:

tep使用者手冊幫你從unittest過渡到pytest

動態新增

使用add()方法動態新增環境變數:

env_vars.add("my_var", 789)

使用環境變數

env_vars返回了類物件例項,通過.運算子來使用環境變數:

env_vars.domain
env_vars.mysql_engine
env_vars.my_var

不需要import,而是給test函式新增引數,如def test(env_vars):

切換環境

conf.yaml檔案中配置:

env: qa

預設為qa環境。

團隊共享公共函式

通過fixture技術,我們可以把重複程式碼提取出來,在團隊間進行復用。tep重度使用了這個技術,在fixtures目錄中,除了預置的fixture_admin.py,可以繼續新增團隊成員的fixture:

tep使用者手冊幫你從unittest過渡到pytest

新新增的fixture_your_name.py需要到根目錄的conftest.py中註冊才能生效:

# Import fixtures
exec("from .fixtures.fixture_admin import *")
exec("from .fixtures.fixture_your_name import *")

conftest.py模組中建議全部定義成fixture,不對外提供function。

為了避免命名衝突和程式碼跟蹤,團隊成員的公共函式命名建議加上_yourname字尾。

訪問MySQL資料庫

首先在fixtures\fixture_admin.py中修改mysql_engine

"mysql_engine": mysql_engine("127.0.0.1",  # host
                             "2306",  # port
                             "root",  # username
                             "123456",  # password
                             "test")  # db_name

依次填寫主機名、埠、使用者名稱、密碼、資料庫名。

接著使用pandas來訪問資料庫,tests\mysql_test.py預置了示例程式碼:

from loguru import logger


def test_mysql(pd, env_vars):
    logger.info(pd.read_sql("select 1 from dual", env_vars.mysql_engine))

返回的資料可以通過data["列名"]["行號"] 的方式讀取。

如果想在console中以表格方式顯示錶資料,可以使用tep.dao.print_db_table()函式,如:

from loguru import logger
from tep.dao import print_db_table


def test_mysql(pd, env_vars):
    data = pd.read_sql("select 1 from dual", env_vars.mysql_engine)
    logger.info(print_db_table(data))

第三方包整合說明

tep使用了Poetry來管理包和依賴:

poetry

目前已整合:

# 造測試資料
faker = "^4.1.1"
# 提取JSON資料
jmespath = "^0.10.0"
# 遮蔽HTTPS警告
urllib3 = "^1.25.9"
# HTTP/HTTPS請求
requests = "^2.24.0"
# HTML測試報告
allure-pytest = "^2.8.16"
allure-python-commons = "^2.8.16"
# 列印日誌
loguru = "^0.5.1"
# 訪問資料庫
pandas = "^1.1.0"
# 配置檔案
pyyaml = "^5.3.1"
# 為pandas訪問資料庫提供engine
sqlalchemy = "^1.3.22"
# 把資料庫表列印成表格
texttable = "^1.6.3"
# 支援sqlalchemy使用
pymysql = "^0.10.1"

東方說

最早寫這個工具的想法是以專案工程方式使用pytest,並結合第三方包完成介面自動化落地。如果你也有類似的想法,那麼可以參考tep的做法。tep使用者手冊是針對於tep工具本身的使用說明,不包含pytest框架搭建和基本使用,如果想入門pytest並深度學習,可以閱讀我寫的pytest系列文章,共8篇。tep的最新版本是0.5.3,還不夠穩定,也存在bug,我會堅持維護下去,既是實用工具,也是技術沉澱。對tep有任何建議或問題,歡迎公眾號後臺回覆“加群”討論哦:

tep使用者手冊幫你從unittest過渡到pytest

參考資料:

原始碼 https://github.com/dongfanger/tep

相關文章