Tep0.6.0更新聊聊Pytest變量接口用例3個級別復用
本文轉載自微信公眾號「PythonMind」,作者dongfanger。轉載本文請聯系PythonMind公眾號。
tep是一款測試工具,在pytest測試框架基礎上集成了第三方包,提供項目腳手架,幫助以寫Python代碼方式,快速實現自動化項目落地。fixture是pytest核心技術,本文聊聊如何使用fixture完成變量、接口、用例3個級別復用。
技術原理
fixture是一種特殊函數,實現了依賴注入,pytest規定,只要在conftest.py模塊中定義了fixture,作為參數傳給測試函數test(fixture_name)就可以使用,無需import。tep在conftest.py上封裝了一層fixtures,類似于Django初始化數據加載的fixtures,定義了env_vars環境變量,預置了登錄接口等。整體思路如下圖所示:
- 實線:表示fixture流轉,從tep.fixture預置fixture,到fixtures,到conftest.py,到tests。
- 虛線:表示動態變量流轉,參考JMeter vars.put()和vars.get(),實現用例級別復用。
- 藍色線:表示靜態變量流轉,參考JMeter自定義用戶變量,實現變量級別復用。
tep.fixture
tep.fixture第一塊內容是預置fixture的實現代碼,如url、faker_ch等,對使用者隱藏。第二塊內容是類TepVar,預置了1個Python字典vars_和2個存取方法put()、get(),劃分了一塊key-value形式存儲區域。
fixtures
fixtures是一個包,里面包括多個fixture_*.py格式的Python模塊,定義的全部都是fixture,只對外提供fixture,不提供function。
自動注冊
conftest.py是pytest的特殊文件,文件名固定,tep在其中實現了自動注冊功能,它會自動查找fixtures目錄下,所有以fixture_開頭,以.py結尾的Python模塊進行導入,無需手動添加。注冊后,tests才能夠找到fixtures中定義的fixture,否則報錯fixture not found。
tests
tests存放所有測試用例,tep建議每個Python模塊中只定義1個test()函數,用例分離,獨立運行。
參考了HttpRunner每個yaml文件1條用例的做法。復雜場景可以定義多個測試test()函數或Test類,pytest都支持。
使用示例
變量級別復用
函數局部變量
- 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())
函數內部變量,作用域是整條測試用例,可以在多個接口之間進行復用,比如參數化和關聯:
全局環境變量
- """ Can only be modified by the administrator. Only fixtures are provided.
- """
- from tep.dao import mysql_engine
- from tep.fixture import *
- @pytest.fixture(scope="session")
- def env_vars(config):
- class Clazz(TepVars):
- env = config["env"]
- """Variables define start"""
- # Environment and variables
- mapping = {
- "qa": {
- "domain": "https://qa.com",
- "mysql_engine": mysql_engine("127.0.0.1", # host
- "2306", # port
- "root", # username
- "123456", # password
- "qa"), # db_name
- },
- "release": {
- "domain": "https://release.com",
- "mysql_engine": mysql_engine("127.0.0.1",
- "2306",
- "root",
- "123456",
- "release"),
- }
- # Add your environment and variables
- }
- # Define properties for auto display
- domain = mapping[env]["domain"]
- mysql_engine = mapping[env]["mysql_engine"]
- """Variables define end"""
- return Clazz()
- @pytest.fixture
- def project_level():
- pass
使用:
- def test(env_vars, env_vars_your_name):
- print(env_vars.common_var)
- print(env_vars_your_name.my_var)
全局環境變量由fixtures提供:
核心數據是env_vars.Clazz類里面的mapping、domain、mysql_engine等屬性:
這么做的目的是為了在PyCharm中敲代碼,輸入.后能自動帶出來,提高編碼效率。fixture_admin.py建議由管理員維護項目級別的公共變量,fixture_your_name.py由團隊成員定義自己的環境變量,避免沖突。它們還有一個區別是fixture_admin.py的env_vars繼承了tep.fixture.TepVar,支持env_vars.put()和env_vars.get()。
變量都由fixture提供。
接口級別復用
tep預置登錄接口fixture_login.py已經實現了接口級別復用,其他接口可以參照實現:
- from tep.client import request
- from tep.fixture import *
- def _jwt_headers(token):
- return {"Content-Type": "application/json", "authorization": f"Bearer {token}"}
- @pytest.fixture(scope="session")
- def login(url):
- # 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
使用:
- from loguru import logger
- def test_login(login):
- logger.info(login.token)
用例級別復用
a_test.py,定義1條測試用例test_a(),使用faker_ch生成隨機name,通過env_vars.put()方法寫入TepVar.vars_中:
- def test_a(faker_ch, env_vars):
- name = faker_ch.name()
- env_vars.put("name", name)
reuse_a_test.py,定義另外1條測試用例test(),import test_a后手動調用執行,從TepVar.vars_中讀取name:
- from tests.sample.case_reuse.a_test import test_a
- def test(faker_ch, env_vars):
- test_a(faker_ch, env_vars)
- print(env_vars.get("name"))
注意test_a()函數參數引用的所有fixture,需要在test()函數參數中重新申明一遍,比如示例中的(faker_ch, env_vars)。
tep是借助conftest.py和fixture,用類變量來做的,參考了JMeter BeanShell的vars。
也可以外接redis。
tep0.6.0更新
tep用戶手冊是根據0.5.3版本寫的,現在更新了0.6.0版本,一是支持本文提到的3個級別復用,微調了fixtures,二是把項目腳手架代碼盡量封裝到tep中,減少后續升級成本。涉及到4個文件:conftest.py、fixture_admin.py、fixture_login.py、fixture_your_name.py。
更新tep
- pip install tep==0.6.0
- 如果還沒有用過tep,使用這條命令安裝后,執行tep startproject project_name就可以創建0.6.0版本的項目腳手架,包含了預置代碼結構和sample測試用例。
- 如果已經安裝了tep,也需要執行這條命令升級0.6.0版本。
老項目升級(可選)
老項目升級也很簡單,先在項目根目錄執行命令:
- tep -U
它會自動替換conftest.py,考慮到老項目fixtures已經有真實數據了,這里給出了version0.6.0文件包,命令執行后在項目根目錄生成:
把老項目的真實數據提取出來,手動替換一下就可以了:
小結
本文介紹了如何使用pytest測試框架實現變量、接口、用例3個級別復用,給出了在tep中的使用示例,然后提供了安裝升級tep0.6.0的方法。這套思路借鑒了JMeter和HttpRunner的部分設計思想,以及我使用過的接口測試平臺經驗,在pytest上實踐了一下。tep只是測試工具,本質上還是寫pytest,感興趣可以試一下哦。
參考資料:源碼 https://github.com/dongfanger/tep