歷史記錄¶
此頁面列出多年來已變更的 pytest 先前版本功能或行為。它們保留在此處作為歷史記錄,以便查看舊程式碼的使用者可以找到與它們相關的文件。
標記改造和反覆¶
在版本 3.6 中變更。
pytest 的標記實作傳統上是透過單純更新函式的 __dict__
屬性,以累積新增標記。結果是,標記會以令人驚訝的方式意外傳遞到類別階層中。此外,擷取它們的 API 不一致,因為參數化的標記會以不同於使用 @pytest.mark
裝飾器套用的標記,以及透過 node.add_marker
新增的標記的方式儲存。
這種狀態在技術上幾乎不可能正確使用來自標記的資料,而沒有深入了解內部結構,導致在更進階的使用中產生細微且難以理解的錯誤。
根據標記是如何宣告/變更,會取得 MarkerInfo
,其中可能包含來自同層類別的標記、MarkDecorators
(當標記來自參數化或 node.add_marker
呼叫時),捨棄先前的標記。此外,MarkerInfo
會像單一標記一樣作用,但實際上它表示對具有相同名稱的多個標記的合併檢視。
最重要的是,標記無法以相同的方式存取模組、類別和函式/方法。事實上,標記只能在函式中存取,即使它們宣告在類別/模組中。
在 pytest 3.6 中已導入新的 API 來存取標記,以解決初始設計的問題,提供 _pytest.nodes.Node.iter_markers()
方法以一致的方式反覆標記,並重新設計內部結構,解決了初始設計中的許多問題。
更新程式碼¶
舊的 Node.get_marker(name)
函式被視為已棄用,因為它會傳回內部 MarkerInfo
物件,其中包含套用至該節點的所有標記的合併名稱、*args
和 **kwargs
。
一般來說,有兩種情境說明標記應如何處理
1. 標記會互相覆寫。順序很重要,但您只想將標記視為單一項目。例如,模組層級的 log_level('info')
可以被特定測試的 log_level('debug')
覆寫。
在這種情況下,請使用
Node.get_closest_marker(name)
# replace this: marker = item.get_marker("log_level") if marker: level = marker.args[0] # by this: marker = item.get_closest_marker("log_level") if marker: level = marker.args[0]
2. 標記以加法方式組成。例如 skipif(condition)
標記表示您只想評估所有標記,順序並不重要。您可能想將您的標記視為這裡的一個集合。
在這種情況下,迭代每個標記並個別處理其
*args
和**kwargs
。# replace this skipif = item.get_marker("skipif") if skipif: for condition in skipif.args: # eval condition ... # by this: for skipif in item.iter_markers("skipif"): condition = skipif.args[0] # eval condition
如果您不確定或有任何疑問,請考慮開啟 一個問題。
快取外掛整合到核心¶
先前以 pytest-cache
為名的第三方外掛來散發 核心快取 外掛的功能。核心外掛與命令列選項和 API 使用方式相容,但您只能在測試執行之間儲存/接收可序列化為 JSON 的資料。
函式參數和 pytest_funcarg__
¶
在 2.3 以前的版本中,沒有 @pytest.fixture
標記,您必須使用函式參數工廠的 pytest_funcarg__NAME
前綴。這仍然存在且會繼續支援,但不再宣傳為宣告函式參數功能的主要方式。
@pytest.yield_fixture
裝飾器¶
在 2.10 版本以前,為了使用 yield
陳述式來執行清除程式碼,必須使用 yield_fixture
標記來標記函式參數。從 2.10 開始,一般函式參數可以使用 yield
,因此 yield_fixture
裝飾器不再需要,且被視為已棄用。
[pytest]
標頭在 setup.cfg
中¶
在 3.0 之前,支援的區段名稱為 [pytest]
。由於這可能會與某些 distutils 指令衝突,setup.cfg
檔案推薦的區段名稱現在為 [tool:pytest]
。
請注意,對於 pytest.ini
和 tox.ini
檔案,區段名稱為 [pytest]
。
將標記套用至 @pytest.mark.parametrize
參數¶
在 3.1 版之前,用於標記值的支援機制使用下列語法
import pytest
@pytest.mark.parametrize(
"test_input,expected", [("3+5", 8), ("2+4", 6), pytest.mark.xfail(("6*9", 42))]
)
def test_eval(test_input, expected):
assert eval(test_input) == expected
這是支援此功能的初始破解,但很快就被證明是不完整的,傳遞函數或套用具有相同名稱但不同參數的多個標記時會中斷。
舊語法計畫在 pytest-4.0 中移除。
@pytest.mark.parametrize
參數名稱作為元組¶
在 2.4 版之前的版本中,需要將參數名稱指定為元組。這仍然有效,但更簡單的 "name1,name2,..."
逗號分隔字串語法現在會優先宣傳,因為它比較容易撰寫且產生的程式碼雜訊較少。
setup:現在是「autouse 固定裝置」¶
在 pytest-2.3 發行前的開發期間,名稱 pytest.setup
已使用,但在發行前已重新命名並移至一般固定裝置機制的其中一部分,即 Autouse 固定裝置(您不必要求的固定裝置)
條件為字串,而非布林值¶
在 pytest-2.4 之前,指定 skipif/xfail 條件的唯一方法是使用字串
import sys
@pytest.mark.skipif("sys.version_info >= (3,3)")
def test_function(): ...
在測試函數設定期間,skipif 條件會透過呼叫 eval('sys.version_info >= (3,0)', namespace)
來評估。命名空間包含所有模組全域變數,以及至少 os
和 sys
。
自 pytest-2.4 起,布林條件 被認為是較佳選擇,因為標記可以自由地匯入測試模組之間。使用字串時,您不僅需要匯入標記,還需要匯入標記使用的所有變數,這會違反封裝。
指定條件為字串的原因是 pytest
可以根據條件字串純粹報告跳過條件的摘要。使用布林條件時,您需要指定 reason
字串。
請注意,字串條件將保持完全支援,如果您不需要跨匯入標記,您可以自由使用它們。
在 pytest.mark.skipif(conditionstring)
或 pytest.mark.xfail(conditionstring)
中對條件字串進行評估會在命名空間字典中進行,該字典的建構方式如下
命名空間初始化時會放入
sys
和os
模組,以及 pytestconfig
物件。使用套用表達式的測試函數的模組全域變數進行更新。
pytest config
物件允許您根據您可能已新增的測試組態值進行跳過
@pytest.mark.skipif("not config.getvalue('db')")
def test_function(): ...
使用「布林條件」的等效方式為
@pytest.mark.skipif(not pytest.config.getvalue("db"), reason="--db was not specified")
def test_function():
pass
注意
您無法在 pytest 的引數解析發生之前匯入的程式碼中使用 pytest.config.getvalue()
。例如, conftest.py
檔案會在命令列解析之前匯入,因此 config.getvalue()
將無法正確執行。
pytest.set_trace()
¶
在版本 2.4 之前,要在程式碼中設定中斷點,需要使用 pytest.set_trace()
import pytest
def test_function():
...
pytest.set_trace() # invoke PDB debugger and tracing
這不再需要,您可以直接使用本機 import pdb;pdb.set_trace()
呼叫。
更多詳細資訊,請參閱 設定中斷點。
「相容性」屬性¶
透過 節點
實例存取 模組
、函式
、類別
、實例
、檔案
和 項目
早已記錄為不建議使用,但從 pytest 3.9
開始會發出警告。
使用者應僅 匯入 pytest
並使用 pytest
模組存取這些物件。