26
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

FastAPIはPythonで高速なAPIサーバーを立てられるので人気ですね。
今回はFastAPIでテストをする方法を試してみました。

FastAPIとは

FastAPIとはPythonでAPIサーバーを構築できるフレームワークで、以下の特徴があります。

  • 軽量
  • Pythonとしては高速
  • Pythonに型定義を実装できる
  • 非同期通信を簡単に実装できる

FastAPI標準のテストツール: TestClient

FastAPIで標準で用意されているテストツールにTestClientというものがあります。
これはテスト内でFastAPIで作ったAPIサーバーのクライアントとして振る舞うことができるものです。

例として以下のmain.pyがあるとします。

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は以下のように書くことができます。

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.pypytestを用いて以下のようにテストすることができます。

% 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のエンドポイントを追加したとします。

main.py
@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!"}

これをテストする関数は次のようになります。

test_main.py
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に以下を追記します。

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"}%

テストは以下のように書けます。
contentbody.json()を渡すことで、POSTのリクエストボディにJSONを渡すことができます。

test_main.py
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をテストすることができそうです。

26
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?