測試探索與命名規則
測試探索(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 匯入模式,避免同名測試檔互相衝突:
testpaths 讓 pytest 只到 tests/ 找測試,專案大時能縮短收集時間。設定檔的完整說明見 設定檔與 conftest.py。
確認哪些測試被找到
不確定 pytest 有沒有找到測試時,用 --collect-only 只列出收集結果而不執行:
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 也能直接拿來只執行某一個測試,見 執行測試與命令列。