前回の記事にあるディレクトリ構成でプロジェクトを作っている前提
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構築
fixture
を conftest.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()
scope
を module
としたが、テストケース間での汚染を排除するなら 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