<aside>
</aside>
지금까지 우리가 추가한 fastapi나 uvicorn은 사용자가 우리 서비스를 이용하기 위해 꼭 필요한, 이른바 '프로덕션(운영) 의존성'이었어요. 하지만 코드를 테스트하거나, 코드 스타일을 검사하는 도구들은 실제 서비스 운영에는 필요 없겠죠? 오늘은 이렇게 개발 과정에서만 필요한 의존성들을 '그룹'으로 묶어 관리하는 법을 배울 거예요. 그리고 실제 테스트 코드 작성을 위해 pytest와 httpx를 도입해 보겠습니다.
poetry add -G dev (또는 -group dev) 명령어로 개발용 의존성을 추가할 수 있습니다.pytest와 httpx를 이용해 FastAPI 엔드포인트에 대한 첫 번째 API 테스트를 작성할 수 있습니다.tests 폴더에 드디어 테스트 코드가 들어갑니다! test_main.py 파일을 새로 만들어 줄 거예요.
todo_api/
├── .venv/
├── poetry.lock
├── pyproject.toml <-- dev 그룹 의존성 추가됨!
├── README.md
├── src/
│ └── todo_api/
│ ├── __init__.py
│ └── main.py
└── tests/
├── __init__.py
└── test_main.py <-- 우리가 추가할 테스트 파일!
pyproject.toml ([tool.poetry.group.dev.dependencies] 섹션 추가)
# ... [project] 섹션 등은 생략 ...
[tool.poetry.group.dev.dependencies]
pytest = "^8.2.2"
httpx = "^0.27.0"
pytest-asyncio = "^0.23.7"
tests/test_main.py
import pytest
from httpx import AsyncClient, ASGITransport
from todo_api.main import app
# 비동기 테스트를 위한 pytest 마커 (기본 strict 모드에서 필요)
@pytest.mark.asyncio
async def test_read_root():
# HTTPX 0.27+ 권장 방식: ASGITransport를 사용해 앱을 연결합니다.
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="<http://test>") as ac:
response = await ac.get("/")
# HTTP 상태 코드가 200 (OK)인지 확인합니다.
assert response.status_code == 200
# 응답 본문(JSON)이 예상과 같은지 확인합니다.
assert response.json() == {"message": "Hello, Todo API!"}
# 참고:
# 앱이 startup/shutdown 등 ASGI lifespan 이벤트에 의존한다면
# from asgi_lifespan import LifespanManager
# async with LifespanManager(app):
# async with AsyncClient(transport=ASGITransport(app=app), base_url="<http://test>") as ac:
# ...
프로젝트의 의존성은 크게 두 종류로 나눌 수 있어요.