Python

Python의 암묵적 마법: FastAPI와 PyTest의 도전 과제

드리프트2 2024. 8. 4. 15:41

 

Python의 FastAPI와 PyTest는 많은 개발자들에게 인기를 끌고 있지만, 이 두 프레임워크의 사용에서 암묵적인 동작 방식이 종종 문제를 일으키고 있습니다.

 

"명시적인 것이 암묵적인 것보다 낫다(explicit is better than implicit)"는 원칙은 개발자들이 코드를 작성하는 데 있어 중요한 기준이지만, 이러한 원칙이 FastAPI와 PyTest에서는 잘 적용되지 않는 경우가 많습니다.

 

이 글에서는 이들 프레임워크의 암묵적 동작 방식에 대한 문제를 분석하고, 이를 해결하기 위한 유용한 노하우를 제시하도록 하겠습니다.

 

PyTest의 암묵적 동작

 

문제점

 

PyTest는 테스트 코드를 작성할 때 바이트코드를 재작성하여 내장된 assert 문을 사용할 수 있도록 합니다.

 

하지만 이로 인해 발생하는 문제는 다음과 같습니다:

  1. 오류 메시지의 불명확성: 헬퍼 메서드에서 assert를 사용할 경우 잘못된 라인 번호가 표시될 수 있습니다.
  2. 모듈 간의 의존성: 모든 테스트 모듈이 PyTest에 의해 재작성되도록 명시적으로 요청해야 하므로, 코드가 복잡해질 수 있습니다.

 

해결 방법

 

헬퍼 메서드에서 assert를 사용할 때 발생하는 문제를 해결하기 위해, 각 모듈에 대해 pytest가 재작성하도록 명시적으로 요청할 수 있습니다.

 

예를 들어, 다음과 같이 헬퍼 함수를 작성할 수 있습니다.

# helpers.py
def assert_equal(actual, expected):
    assert actual == expected, f"Expected {expected}, but got {actual}"

 

이 헬퍼 함수를 테스트에서 직접 사용하면, 오류 메시지가 명확하게 표시됩니다.

 

또한, fixture를 사용할 때는 명시적으로 작성하여 가독성을 높일 수 있습니다.

 

예를 들어, 다음과 같이 conftest.py 파일을 설정하여 전역 의존성을 관리할 수 있습니다.

# conftest.py
import pytest

@pytest.fixture
def sample_database():
    # 데이터베이스 초기화 로직
    db = create_test_db()
    yield db
    # 데이터베이스 종료 로직
    db.close()

 

이렇게 설정하면, 모든 테스트에서 sample_database를 사용할 수 있으며, 테스트 전에 자동으로 초기화되고 종료됩니다.

 

FastAPI의 의존성 문제

 

문제점

 

FastAPI는 경로 함수가 호출될 때 의존성을 식별자 이름에 따라 자동으로 해결합니다.

 

그러나 다음과 같은 문제가 발생할 수 있습니다:

  1. 전역 의존성의 관리: 의존성을 전역 범위에 설정해야 하므로 복잡성이 증가합니다.
  2. 장식자 사용의 문제: 경로 함수가 앱과 함께 데코레이트되면, 해당 앱에 암묵적으로 추가되므로, 모듈 간의 분리가 어렵습니다.

 

해결 방법

 

FastAPI의 의존성을 보다 명시적으로 관리하기 위해, 의존성을 주입하는 방법을 활용할 수 있습니다.

 

예를 들어, 아래와 같이 명시적으로 의존성을 주입할 수 있습니다.

# main.py
from fastapi import FastAPI, Depends

app = FastAPI()

def get_db():
    db = create_database()
    try:
        yield db
    finally:
        db.close()

@app.get("/items/")
async def read_items(db: Session = Depends(get_db)):
    items = db.query(Item).all()
    return items

 

이렇게 설정하면, get_db 함수가 명시적으로 호출되며, 데이터베이스 세션이 각 요청에 대해 관리됩니다.

 

또한, FastAPI의 APIRouter를 사용하여 경로를 모듈화할 수 있습니다.

 

아래와 같이 별도의 모듈로 라우트를 분리할 수 있습니다

# routers/items.py
from fastapi import APIRouter, Depends
from .dependencies import get_db

router = APIRouter()

@router.get("/")
async def read_items(db: Session = Depends(get_db)):
    items = db.query(Item).all()
    return items

 

이렇게 하면, 경로를 명확히 분리할 수 있으며, 의존성을 명시적으로 주입하여 코드의 가독성을 높일 수 있습니다.

 

 

결론

 

FastAPI와 PyTest의 암묵적 동작 방식은 개발자들이 직면하는 여러 문제를 야기합니다.

 

그러나 이러한 문제는 명확한 코드 구조와 의존성 관리를 통해 해결할 수 있습니다.

  • PyTest에서는 헬퍼 메서드를 명확히 정의하고, fixture를 활용하여 테스트 환경을 관리함으로써 가독성과 유지 보수성을 높일 수 있습니다.
  • FastAPI에서는 의존성을 명시적으로 정의하고, APIRouter를 사용하여 경로를 모듈화함으로써 코드의 명확성을 증진할 수 있습니다.

이러한 전략을 통해 개발자는 Python 생태계에서의 암묵적 마법을 극복하고, 더욱 읽기 쉽고 유지 관리하기 쉬운 코드를 작성할 수 있습니다.

 

이러한 노하우는 복잡한 애플리케이션을 개발하는 데 많은 도움이 될 것입니다.