<aside>

</aside>

챕터 소개 🚀

지금까지 우리가 추가한 fastapiuvicorn은 사용자가 우리 서비스를 이용하기 위해 꼭 필요한, 이른바 '프로덕션(운영) 의존성'이었어요. 하지만 코드를 테스트하거나, 코드 스타일을 검사하는 도구들은 실제 서비스 운영에는 필요 없겠죠? 오늘은 이렇게 개발 과정에서만 필요한 의존성들을 '그룹'으로 묶어 관리하는 법을 배울 거예요. 그리고 실제 테스트 코드 작성을 위해 pytesthttpx를 도입해 보겠습니다.


챕터 목표 🎯


이번 챕터에서 사용되는 전체 코드 및 프로젝트 구조 📂

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:
#         ...


강의 내용 📖

의존성에도 종류가 있다? 그룹으로 관리하기! 🗂️

프로젝트의 의존성은 크게 두 종류로 나눌 수 있어요.