詳解如何利用Pytest?Cache?Fixture實(shí)現(xiàn)測試結(jié)果緩存
前言
接口自動(dòng)關(guān)過程中,經(jīng)常會(huì)遇到這樣一些場景,"請求2需要用到請求1響應(yīng)的數(shù)據(jù)",常見的做法,進(jìn)行用例依賴或者將請求1的響應(yīng)結(jié)果寫入一個(gè)文件,用到的時(shí)候讀取文件。當(dāng)然這都不是這篇文章的重點(diǎn),本片文章主要介紹cache
寫入和讀取緩存數(shù)據(jù)。
request.config.cache
還不了解request fixture
的同學(xué)可以先看看這篇文章,pytest 的 request fixture:實(shí)現(xiàn)個(gè)性化測試需求
我們先看看使用案例:
def test_01(cache): ? ?cache.set("token", "uiouoouoiou") ? def test_02(cache): ? ?r = cache.get("token", None)
這樣段代碼在執(zhí)行test_01
會(huì)將token
值緩存,任何執(zhí)行test_02
時(shí)就可以從緩存中讀取token
值。那Cache
是如何實(shí)現(xiàn)的呢?我們一起來看看源碼。源碼直達(dá)
實(shí)現(xiàn)原理
def test_01(cache): ? ?cache.set("token", {"token": "1212121"})
我們在cache.set()
這一行進(jìn)行斷點(diǎn),debug
執(zhí)行后,debug
結(jié)果為
cache = Cache()
_CACHE_PREFIX_DIRS = 'd'
_CACHE_PREFIX_VALUES = 'v'
_cachedir = /PycharmProjects/panda-test/org/.pytest_cache
_config = <_pytest.config.Config object at 0x109e80d60>
可以看到會(huì)自動(dòng)創(chuàng)建一個(gè)緩存實(shí)例,而且初始化了一些數(shù)據(jù),默認(rèn)應(yīng)該緩存文件會(huì)在.pytest_cache
目錄下
/_pytest/cacheprovider.py
@fixture def cache(request: FixtureRequest) -> Cache: ? ?"""Return a cache object that can persist state between testing sessions. ? ? cache.get(key, default) ? cache.set(key, value) ? ? Keys must be ``/`` separated strings, where the first part is usually the ? name of your plugin or application to avoid clashes with other cache users. ? ? Values can be any object handled by the json stdlib module. ? """ ? ?assert request.config.cache is not None ? ?return request.config.cache
可以看到,cache
返回的是Cache
對象,我們看看Cache
對象是如何實(shí)現(xiàn)的
? ?def set(self, key: str, value: object) -> None: ? ? ? ?path = self._getvaluepath(key) ? ? ? ?try: ? ? ? ? ? ?if path.parent.is_dir(): ? ? ? ? ? ? ? ?cache_dir_exists_already = True ? ? ? ? ? ?else: ? ? ? ? ? ? ? ?cache_dir_exists_already = self._cachedir.exists() ? ? ? ? ? ? ? ?path.parent.mkdir(exist_ok=True, parents=True) ? ? ? ?except OSError: ? ? ? ? ? ?self.warn("could not create cache path {path}", path=path, _ispytest=True) ? ? ? ? ? ?return ? ? ? ?if not cache_dir_exists_already: ? ? ? ? ? ?self._ensure_supporting_files() ? ? ? ?data = json.dumps(value, ensure_ascii=False, indent=2) ? ? ? ?try: ? ? ? ? ? ?f = path.open("w", encoding="UTF-8") ? ? ? ?except OSError: ? ? ? ? ? ?self.warn("cache could not write path {path}", path=path, _ispytest=True) ? ? ? ?else: ? ? ? ? ? ?with f: ? ? ? ? ? ? ? ?f.write(data)
這段源碼就是用來將鍵值對保存到緩存中。代碼比較簡單,簡單解釋一下
- 獲取要保存的鍵值對的路徑:通過調(diào)用
_getvaluepath()
方法,根據(jù)給定的鍵(key
)獲取值(value
)在緩存中的路徑(path
)。這里的路徑是一個(gè)字符串,使用/
分隔不同的層級,通常第一個(gè)名稱是插件或應(yīng)用程序的名稱。 - 檢查路徑是否存在:通過判斷路徑的父目錄是否為目錄來確定是否需要?jiǎng)?chuàng)建路徑。如果父目錄已經(jīng)存在,則
cache_dir_exists_already
設(shè)置為True
;否則,它會(huì)檢查緩存目錄是否存在,并且如果緩存目錄已經(jīng)存在,則cache_dir_exists_already
設(shè)置為True
,否則創(chuàng)建緩存目錄。 - 確保支持文件已存在:如果緩存目錄是新創(chuàng)建的,則調(diào)用
_ensure_supporting_files()
方法確保支持文件存在。這個(gè)方法可能是用來創(chuàng)建其他與緩存相關(guān)的文件或目錄。 - 序列化數(shù)據(jù)并寫入文件:將值(
value
)使用 JSON 格式進(jìn)行序列化,以確保它是基本的 Python 類型或包含了嵌套類型(例如列表和字典)。然后,嘗試打開路徑對應(yīng)的文件(使用 UTF-8 編碼),并將序列化后的數(shù)據(jù)寫入文件中。
? ?def get(self, key: str, default): ? ? ? ?path = self._getvaluepath(key) ? ? ? ?try: ? ? ? ? ? ?with path.open("r", encoding="UTF-8") as f: ? ? ? ? ? ? ? ?return json.load(f) ? ? ? ?except (ValueError, OSError): ? ? ? ? ? ?return default
這段源碼用來從緩存中獲取指定鍵的值,簡單解釋一下:
- 獲取要獲取值的路徑:通過調(diào)用
_getvaluepath()
方法,根據(jù)給定的鍵(key
)獲取值在緩存中的路徑(path
)。這里的路徑是一個(gè)字符串,使用/
分隔不同的層級,通常第一個(gè)名稱是插件或應(yīng)用程序的名稱。 - 嘗試讀取文件并返回已緩存的值:使用路徑對應(yīng)的文件(使用 UTF-8 編碼)打開,并使用
json.load(f)
將文件中的數(shù)據(jù)加載為 Python 對象。然后將加載的值返回。 - 處理異常情況:如果無法將文件中的內(nèi)容解析為有效的 JSON 數(shù)據(jù)或者打開文件失敗,則捕獲異常(
ValueError
和OSError
),并返回默認(rèn)值(default
)。
這里還是學(xué)習(xí)到了一種新奇的寫法,以前沒用過with path.open("r", encoding="UTF-8") as f:
等價(jià)于open(path, "r", encoding="UTF-8")
這是兩個(gè)常用的方法,當(dāng)然還提供了更多方法,這里簡單介紹一下:
__init__(self, cachedir: Path, config: Config, *, _ispytest: bool = False) -> None
:
初始化方法,用于設(shè)置類的屬性 _cachedir
和 _config
。
for_config(cls, config: Config, *, _ispytest: bool = False) -> "Cache"
:
- 類方法,根據(jù)給定的配置信息創(chuàng)建并返回
Cache
實(shí)例。 - 如果配置項(xiàng)
cacheclear
設(shè)置為True
,并且緩存目錄存在,則調(diào)用clear_cache
方法清空緩存。 - 最后返回一個(gè)新的
Cache
實(shí)例。
clear_cache(cls, cachedir: Path, _ispytest: bool = False) -> None
:
- 類方法,清空緩存目錄下的子目錄。
- 根據(jù)參數(shù)
cachedir
構(gòu)建子目錄路徑,并使用rm_rf
函數(shù)遞歸刪除該目錄。
cache_dir_from_config(config: Config, *, _ispytest: bool = False) -> Path
:
- 靜態(tài)方法,從給定的配置信息中獲取緩存目錄的路徑。
- 首先從配置中獲取緩存目錄的字符串表示,然后使用
resolve_from_str
函數(shù)將其解析為Path
對象返回。
warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None
:
- 發(fā)出緩存警告的方法。
- 使用
warnings.warn
函數(shù)發(fā)出警告信息,并指定警告類型為PytestCacheWarning
。 - 如果存在參數(shù)
args
,則將其作為格式化參數(shù)替換格式字符串中的占位符。
mkdir(self, name: str) -> Path
:
- 創(chuàng)建一個(gè)目錄路徑對象,并在緩存目錄下創(chuàng)建該目錄。
- 參數(shù)
name
是要?jiǎng)?chuàng)建的目錄名稱。 - 檢查目錄名是否包含路徑分隔符
/
,如果有則拋出異常。 - 使用
_cachedir.joinpath
方法構(gòu)建完整的目錄路徑,并使用mkdir
方法創(chuàng)建目錄。 - 返回創(chuàng)建的目錄路徑對象。
_getvaluepath(self, key: str) -> Path
:
- 根據(jù)給定的鍵生成值文件的路徑。
- 在緩存目錄下構(gòu)建值文件路徑,使用
_CACHE_PREFIX_VALUES
作為子目錄前綴。
_ensure_supporting_files(self) -> None
:
- 創(chuàng)建緩存目錄中的支持文件。
- 創(chuàng)建
README.md
文件,用于說明緩存目錄的用途。 - 創(chuàng)建
.gitignore
文件,忽略緩存目錄下的所有文件。 - 創(chuàng)建
CACHEDIR.TAG
文件,用于標(biāo)記緩存目錄。
最后
cache
功能還是很實(shí)用的,比如登錄功能,可以在登錄之后,將token
寫入緩存,這樣進(jìn)行其他接口請求時(shí),需要token
時(shí)直接從緩存獲取token
即可。
到此這篇關(guān)于詳解如何利用Pytest Cache Fixture實(shí)現(xiàn)測試結(jié)果緩存的文章就介紹到這了,更多相關(guān)Pytest Cache Fixture內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析PHP與Python進(jìn)行數(shù)據(jù)交互
本篇文章給大家分享了PHP與Python進(jìn)行數(shù)據(jù)交互的詳細(xì)方法以及重點(diǎn)點(diǎn)撥,有興趣的朋友可以學(xué)習(xí)下。2018-05-05使用Python中tkinter庫簡單gui界面制作及打包成exe的操作方法(二)
這篇文章主要介紹了使用Python中tkinter庫簡單gui界面制作及打包成exe的操作方法(二),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10