FastAPI 測試 (Testing)

由於 FastAPI 是基於 Starlette,它使得撰寫測試變得非常簡單且直觀。你可以使用 TestClient,它會模擬發送 HTTP 請求到你的 FastAPI 應用程式,但實際上並沒有真的啟動伺服器 (透過程式內部呼叫),因此速度極快。

推薦搭配 pytest 作為測試框架。

安裝測試依賴

你需要安裝 httpx (TestClient 的底層) 和 pytest

pip install httpx pytest

撰寫測試程式

假設你的 main.py 如下:

# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_main():
    return {"msg": "Hello World"}

我們可以建立一個 test_main.py 檔案:

# test_main.py
from fastapi.testclient import TestClient
from .main import app # 假設 main.py 在同一層目錄

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"msg": "Hello World"}

執行測試

在終端機執行:

pytest

你應該會看到類似這樣的結果:

================ test session starts ================
platform darwin -- Python 3.9.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /path/to/project
collected 1 item

test_main.py .                                            [100%]

================ 1 passed in 0.03s =================

測試參數輸入

你可以像使用 Python requests 庫一樣,傳送 JSON、Query 參數或 Header。

def test_create_item():
    response = client.post(
        "/items/",
        headers={"X-Token": "coneofsilence"},
        json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
    )
    assert response.status_code == 200
    assert response.json() == {
        "id": "foobar",
        "title": "Foo Bar",
        "description": "The Foo Barters",
    }

依賴覆寫 (Override Dependencies)

這是 FastAPI 測試最強大的功能之一。 在測試時,你通常不想真的連到外部資料庫或發送真實的 Email。你可以用 app.dependency_overrides 來替換掉原本的依賴項。

假設你有一個依賴:

# main.py
from typing import Annotated

async def get_db():
    # ... 連接真實資料庫 ...
    pass

@app.get("/items/")
async def read_items(db: Annotated[Any, Depends(get_db)]):
    pass

在測試中,你可以這樣替換它:

# test_main.py
from .main import app, get_db

async def override_get_db():
    # ... 回傳一個 Mock 的資料庫 session 或物件 ...
    yield mock_db_session

# 設定覆寫
app.dependency_overrides[get_db] = override_get_db

def test_read_items():
    response = client.get("/items/")
    assert response.status_code == 200

    # 測試結束後還原 (如果需要)
    app.dependency_overrides = {}

總結

  • 使用 TestClient 進行 API 測試,它基於 httpx,用法與 requests 相似。
  • 使用 pytest 執行測試。
  • 利用 app.dependency_overrides 來 Mock 資料庫或其他外部依賴,這是撰寫高品質單元測試的關鍵。