Marker
Marker 是貼在測試上的標籤,寫法是 @pytest.mark.名稱。內建 marker 能控制測試是否執行,例如 skip 跳過、skipif 有條件跳過、xfail 預期失敗;自訂 marker 則用來分類,例如把慢的測試標成 slow,再用 -m 選擇要不要執行。
跳過測試:skip 與 skipif
import sys
import pytest
@pytest.mark.skip(reason="金流沙盒維護中")
def test_payment():
...
@pytest.mark.skipif(sys.platform == "win32", reason="只在 Linux/macOS 上測試")
def test_unix_permission():
...
skipif 的條件在收集測試時就會判斷。reason 一定要寫,執行 pytest -ra 時會顯示在摘要裡,讓人知道為什麼跳過。
需要在測試執行中途才決定跳過時,呼叫 pytest.skip();缺少選用套件時,可以用 pytest.importorskip():
def test_with_numpy():
np = pytest.importorskip("numpy") # 沒安裝 numpy 就跳過
assert np.array([1, 2]).sum() == 3
預期失敗:xfail
xfail 表示「已知這個測試目前會失敗」,例如 bug 已回報但還沒修好。失敗時顯示 x(xfailed),不會讓整體測試失敗:
@pytest.mark.xfail(reason="issue #42:負數價格尚未檢查")
def test_negative_price():
with pytest.raises(ValueError):
apply_discount(-100, 10)
skip 和 xfail 差在哪?
skip 根本不執行測試;xfail 會執行,只是失敗也不算錯。xfail 的測試若意外通過,會顯示 X(xpassed),提醒你 bug 可能已經修好、可以拿掉標記了。加上 strict=True 時,意外通過會被當成失敗,確保標記不會被遺忘。
自訂 marker 為測試分類
用 -m 選擇:
為什麼要註冊 marker?
自訂 marker 應該在設定檔中註冊。沒註冊時 pytest 只會發出警告,打錯字(例如 @pytest.mark.slwo)不容易發現;加上 --strict-markers 後,未註冊的 marker 會直接報錯:
[tool.pytest]
addopts = ["--strict-markers"]
markers = [
"slow: 執行時間較長的測試",
"integration: 會呼叫外部服務的整合測試",
]
註冊後執行 pytest --markers 就能看到所有 marker 與說明。
套用到整個類別或檔案
marker 加在類別上會套用到其中所有測試;要套用到整個檔案,在模組層級設定 pytestmark:
推薦影音
pytest Markers - Custom and Built-In Markers for Test Filtering
BugBytes 約 15 分鐘的示範,依序介紹 skip、skipif、xfail、自訂 marker,以及用 -m 篩選要執行的測試,最後提到 pytest-django 的 django_db marker。