1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FastAPIプロジェクトのユニットテスト

Last updated at Posted at 2024-11-06

前回の記事にあるディレクトリ構成でプロジェクトを作っている前提
https://qiita.com/yuki-alost/items/1275885310a808440463

インポートパス設定

プロジェクトルートに pyproject.toml を設置して以下の内容を記載

[tool.pytest.ini_options]
pythonpath = "src"
testpaths = ["tests",]

これにより src 以下の相対パスで import 文が書けるようになる

pytest導入

以下を実行

  • pipenv install -d pytest

  • pipenv install -d pytest-mock

  • pipenv install -d httpx

    標準の unittest モジュールよりも高機能なのでこちらの使用を推奨
    ついでにHTTPリクエストの実行に必要なモジュールもインストール

ディレクトリ構成

API以外のテストも実装することを想定し、ディレクトリを分けておく

  + [project-root]
     +-- src
          +-- 略
     +-- tests
          +-- api
               +-- conftest.py  # api下のテストケースにのみ適用したいfixture
               +-- foo_test.py
               +-- bar_test.py
          +-- controller
               +-- .gitkeep
          +-- models
               +-- .gitkeep
          +-- conftest.py  # 全テストケースに適用したいfixture (空でも良い)
     +-- Pipfile
     +-- pyproject.toml

fixture構築

fixtureconftest.py に実装していく

  • fixture はテストの前処理/後処理に関する記法
  • xUnit 系の setUp/tearDown の仕組みに相当する

以下、APIのテスト用サーバの起動を tests/api/conftest.py に実装する

別プロセスで uvicorn を起動する実装とした

import multiprocessing
import os
import pytest
import uvicorn

from fastapi import FastAPI

from api.foo import foo_router
from api.bar import bar_router


def open_test_server(port: str):
    app = FastAPI()
    app.include_router(foo_router)
    app.include_router(bar_router)
    uvicorn.run(app, host='0.0.0.0', port=port)

@pytest.fixture(scope='module', autouse=True)
def setup_module():
    port = os.getenv('TEST_PORT', '8000')
    server_process = multiprocessing.Process(target=open_test_server, args=(port, ))
    server_process.start()
    yield
    server_process.terminate()
    server_process.join()

scopemodule としたが、テストケース間での汚染を排除するなら function が妥当
テストケースごとに都度プロセスが起動/終了する負荷を嫌うなら module で良い

テストケース実装

import httpx
import os


TEST_HOST: str = 'localhost'
TEST_PORT: str = os.getenv('TEST_PORT', '8000')
TEST_SERVER: str = f'http://{TEST_HOST}:{TEST_PORT}'


def test_foo():
    api_path = '/foo'
    response = httpx.get(f'{TEST_SERVER}{api_path}')
    assert response.status_code == 200

def test_foo_create():
    api_path = '/foo/create'
    response = httpx.get(f'{TEST_SERVER}{api_path}')
    assert response.status_code == 200

def test_foo_update():
    api_path = '/foo/update'
    response = httpx.get(f'{TEST_SERVER}{api_path}')
    assert response.status_code == 200

テスト実行

  • pipenv run pytest
1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?