FastAPIはPythonで高速なAPIサーバーを立てられるので人気ですね。
今回はFastAPIでテストをする方法を試してみました。
FastAPIとは
FastAPIとはPythonでAPIサーバーを構築できるフレームワークで、以下の特徴があります。
- 軽量
- Pythonとしては高速
- Pythonに型定義を実装できる
- 非同期通信を簡単に実装できる
FastAPI標準のテストツール: TestClient
FastAPIで標準で用意されているテストツールにTestClient
というものがあります。
これはテスト内でFastAPIで作ったAPIサーバーのクライアントとして振る舞うことができるものです。
例として以下のmain.py
があるとします。
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
async def check_health():
return {"msg": "Hello World"}
これをローカルで立ち上げたとき、以下の結果が返ってくることが期待されます。
% curl http://localhost:8000/health
{"message":"Hello World!"}
この動作をTestClient
を使って、ユニットテストとしてテストしたいです。
これをテストするtest_main.py
は以下のように書くことができます。
from fastapi.testclient import TestClient
from main import app # main.pyで作ったapp = FastAPI()をimport
client = TestClient(app) # テスト用クライアントの生成
def test_check_health():
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}
このtest_main.py
はpytest
を用いて以下のようにテストすることができます。
% pytest test_main.py
========================== test session starts ===========================
platform darwin -- Python 3.11.2, pytest-7.4.0, pluggy-1.2.0
rootdir: /path/to/directory
plugins: mock-3.11.1, anyio-3.7.1
collected 2 items
test_main.py .. [100%]
=========================== 1 passed in 1.19s ============================
このようにして、main.py
で作ったAPIサーバーの振る舞いを簡単にテストすることができます。
クエリパラメータを使う
main.py
に以下のように/hello
のエンドポイントを追加したとします。
@app.get("/hello")
def hello(name: str):
return {"message": f"Hello {name}!"}
期待される動作は以下の通りです。
% curl "http://0.0.0.0:8000/hello?name=Bob"
{"message":"Hello Bob!"}
これをテストする関数は次のようになります。
def test_hello():
response = client.get("/hello", params={"name": "Bob"})
assert response.status_code == 200
assert response.json() == {"message": "Hello Bob!"}
クエリパラメータを伴うエンドポイントをテストしたいときは、client.get()
の中で、params
に対し辞書型でパラメータを与えることでテストできます。
POSTのテスト
ここまでGETメソッドを見てきましたが、POSTメソッドについても示します。
まずmain.py
に以下を追記します。
from pydantic import BaseModel
## 中略
class Message(BaseModel):
sender: str
message: str
@app.post("/send")
def send(msg: Message):
return {"message": f"{msg.message} sent by {msg.sender}"}
このAPIで期待される動作は以下の通りです。
% curl -X POST http://localhost:8000/send \
> -H "Content-Type: application/json" \
> -d '{"sender": "Bob", "message": "Hi, Alice."}'
{"message":"Hi, Alice. sent by Bob"}%
テストは以下のように書けます。
content
にbody.json()
を渡すことで、POSTのリクエストボディにJSONを渡すことができます。
from main import app, Message # 追記
## 中略
def test_send():
body = Message(sender="Bob", message="Hi, Alice.")
response = client.post("/send", content=body.json())
assert response.status_code == 200
assert response.json() == {"message": "Hi, Alice. sent by Bob"}
おわりに
TestClient
を用いることで、FastAPIでAPIとしての振る舞いを簡単にテストすることができます。
ここで試した以外にも、ヘッダーやCookieなどの付与も簡単にできるので、様々なAPIをテストすることができそうです。