2026년 7월 21일 화요일

test_main.py



"""
pytest가 test_main.py를 자동으로 찾아내어 가상의 웹 서버를 띄우고, 엔드포인트를 때린 뒤, 내부에서 러스트 비동기 코드가 구글 시트나 외부 API를 긁어오는 전 과정을 단 1초 만에 검증하고 종료합니다.
💡 FastAPI 테스트 꿀팁
진짜 서버를 띄우지 않음: ASGITransport(app=app) 방식은 네트워크 포트(예: 8000번)를 실제로 열지 않고, 메모리 내부에서 FastAPI의 라우팅 유닛을 직접 호출하기 때문에 테스트 속도가 무지막지하게 빠릅니다.
pytest 기능 분리: 만약 파일이 많아지면 pytest -v test_main.py 처럼 특정 파일만 지정해서 테스트할 수도 있습니다.

"""

import pytest
from httpx import ASGITransport, AsyncClient

from main import app  # FastAPI 앱 임포트


@pytest.mark.asyncio
async def test_fastapi_fetch_success():
  # 1. FastAPI 앱을 구동할 비동기 테스트 클라이언트 생성
  transport = ASGITransport(app=app)
  async with AsyncClient(transport=transport, base_url="http://test") as ac:
    # 2. 테스트용 타겟 URL을 파라미터로 넘겨 우리 API를 호출
    target = "https://httpbin.org"
    response = await ac.get(f"/fetch-data?target_url={target}")

    # 3. 결과 검증 (Then)
    assert response.status_code == 200

    res_json = response.json()
    assert res_json["status"] == "success"
    assert res_json["length"] > 0
    assert "data_preview" in res_json


@pytest.mark.asyncio
async def test_fastapi_fetch_bad_url():
  transport = ASGITransport(app=app)
  async with AsyncClient(transport=transport, base_url="http://test") as ac:
    # 잘못된 URL을 보냈을 때 FastAPI가 500 에러를 잘 뱉는지 테스트
    invalid_target = "https://this-is-invalid-url-12345.com"
    response = await ac.get(f"/fetch-data?target_url={invalid_target}")

    assert response.status_code == 500
    assert "Request failed" in response.json()["detail"]


database.py

import os from contextlib import contextmanager # contextmanager 임포트 from typing import Generator from dotenv...