跳轉至

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

Fixture

Fixture 是 pytest 用來準備測試環境的函式:例如建立測試資料、開啟資料庫連線、產生暫存檔,測試只要在參數列寫上 fixture 名稱,pytest 就會自動執行它並把結果傳進來。Fixture 讓準備與清理的程式碼可以重複使用,也是 pytest 與 unittest 最大的差異。

為什麼需要 fixture?

多個測試都需要同一份資料時,直接複製貼上會讓測試又長又難維護。改成 fixture:

import pytest


@pytest.fixture
def cart():
    return {"apple": 30, "banana": 15}


def test_cart_total(cart):
    assert sum(cart.values()) == 45


def test_cart_has_apple(cart):
    assert "apple" in cart

pytest 看到 test_cart_total 的參數叫 cart,就去找同名的 fixture 執行,並把回傳值傳入。這種依名稱自動注入的方式稱為依賴注入(dependency injection)。

每個測試拿到的都是全新的 cart。即使某個測試修改了它,也不會影響其他測試,這是測試能彼此獨立的關鍵。

用 yield 做清理(teardown)

需要「用完要收拾」的資源,例如檔案、連線、啟動的伺服器,用 yield 取代 return:yield 之前是準備,之後是清理。

import sqlite3

import pytest


@pytest.fixture
def db():
    conn = sqlite3.connect(":memory:")
    conn.execute("CREATE TABLE users (name TEXT)")
    yield conn          # 把連線交給測試
    conn.close()        # 測試結束後一定會執行,即使測試失敗


def test_insert_user(db):
    db.execute("INSERT INTO users VALUES ('Amy')")
    assert db.execute("SELECT COUNT(*) FROM users").fetchone()[0] == 1

Fixture 的範圍(scope)

預設每個測試都會重新執行 fixture(scope="function")。建立成本很高的資源,例如資料庫或瀏覽器,可以放大範圍讓多個測試共用:

scope 建立次數
function(預設) 每個測試一次
class 每個測試類別一次
module 每個 .py 檔一次
package 每個套件(資料夾)一次
session 整次 pytest 執行只建立一次
@pytest.fixture(scope="session")
def browser():
    b = launch_browser()   # 假設是很慢的操作
    yield b
    b.quit()

共用範圍越大,越要小心狀態外洩

session 範圍的物件被某個測試修改後,後面的測試會看到修改後的狀態,造成「單獨跑會過、一起跑會失敗」的問題。共用的資源最好是唯讀的,或在每個測試前重設。

Fixture 可以依賴其他 fixture

Fixture 的參數也能是其他 fixture,pytest 會自動依序建立:

@pytest.fixture
def user():
    return {"name": "Amy", "vip": True}


@pytest.fixture
def vip_cart(user, cart):
    return {"owner": user["name"], "items": cart, "discount": 10}


def test_vip_discount(vip_cart):
    assert vip_cart["discount"] == 10

一個 fixture 只負責一件事,再組合起來,比寫一個什麼都做的大 fixture 更容易維護。

在多個檔案之間共用:conftest.py

寫在測試檔裡的 fixture 只有該檔能用。放進同一資料夾(或上層資料夾)的 conftest.py,該資料夾以下所有測試都能直接使用,不需要 import:

tests/conftest.py
import pytest


@pytest.fixture
def cart():
    return {"apple": 30, "banana": 15}

conftest.py 的更多用途見 設定檔與 conftest.py。

其他常用技巧

  • autouse=True:讓 fixture 自動套用到範圍內所有測試,不必寫在參數列,適合「每個測試前都要重設」的情況。請節制使用,否則讀測試時看不出有哪些隱藏的準備動作。
  • @pytest.mark.usefixtures("名稱"):只需要 fixture 的副作用、不需要它的回傳值時使用。
  • pytest --fixtures:列出目前可用的所有 fixture 與說明,包含 pytest 內建的 fixture。

推薦影音

pytest: everything you need to know about fixtures

pytest 核心開發者 Anthony Sottile 約 20 分鐘的 fixture 專題,逐一說明 fixture 的各種選項與使用情境,適合讀完本頁後用來複習與補充細節。

Sharing is Caring - Sharing pytest Fixtures(PyCascades 2023)

《Python Testing with pytest》作者 Brian Okken 的演講,說明如何把團隊寫好的 fixture 打包成 pytest 外掛,在多個專案之間共用,適合已熟悉 fixture、想進一步整理大型測試的讀者。