跳轉至

建立 2026-10-11 更新 2026-10-11

測試探索與命名規則

測試探索(test discovery)是 pytest 自動尋找測試的機制:它會從執行目錄往下搜尋 test_*.py 或 *_test.py 檔案,收集裡面以 test 開頭的函式與 Test 開頭的類別方法。測試沒被執行,九成是命名不符合這套規則。

預設的探索規則

對象 規則 例子
檔案 test_*.py 或 *_test.py test_shop.py、shop_test.py
函式 名稱以 test 開頭 def test_total():
類別 名稱以 Test 開頭,且不能有 __init__ class TestCart:
類別中的方法 名稱以 test 開頭 def test_add(self):
資料夾 遞迴搜尋,但略過 .git、venv、build 等常見目錄 tests/unit/

常見陷阱

  • 檔案取名 tests_shop.py、shop_tests.py:不符合規則,整個檔案被忽略。
  • 類別定義了 __init__:pytest 會跳過整個類別並發出警告。
  • 兩個不同資料夾都有 test_utils.py:在預設匯入模式下會發生名稱衝突,需在資料夾內放 __init__.py,或改用下文的 importlib 匯入模式。

用類別整理相關測試

同一功能的測試可以放進 Test 類別裡分組。和 unittest 不同,類別不需要繼承任何東西:

tests/test_cart.py
class TestCart:
    def test_empty_cart_total_is_zero(self):
        assert sum([]) == 0

    def test_total_adds_prices(self):
        assert sum([100, 250]) == 350

pytest 會為每個測試方法建立新的類別實例,所以方法之間不會共用 self 上的狀態。需要共用的準備工作應該寫成 fixture。

建議的資料夾結構

把測試集中在專案根目錄的 tests/ 資料夾,並把被測程式放在 src/ 底下(稱為 src layout):

my_project/
├── pyproject.toml
├── src/
│   └── my_package/
│       ├── __init__.py
│       └── shop.py
└── tests/
    ├── conftest.py
    └── test_shop.py

src layout 的好處是測試一定會匯入「已安裝的套件」,而不是剛好在目前資料夾裡的檔案,能及早發現打包設定的錯誤。用 uv 建立專案並以 uv sync 安裝後,測試裡直接寫 from my_package.shop import apply_discount 即可。

pytest 官方建議新專案使用 importlib 匯入模式,避免同名測試檔互相衝突:

pyproject.toml
[tool.pytest]
addopts = ["--import-mode=importlib"]
testpaths = ["tests"]

testpaths 讓 pytest 只到 tests/ 找測試,專案大時能縮短收集時間。設定檔的完整說明見 設定檔與 conftest.py。

確認哪些測試被找到

不確定 pytest 有沒有找到測試時,用 --collect-only 只列出收集結果而不執行:

pytest --collect-only -q
tests/test_cart.py::TestCart::test_empty_cart_total_is_zero
tests/test_cart.py::TestCart::test_total_adds_prices
tests/test_shop.py::test_apply_discount

3 tests collected in 0.01s

每一行是一個測試的節點 ID(node ID),格式為 檔案路徑::類別::函式。這個 ID 也能直接拿來只執行某一個測試,見 執行測試與命令列。