본문으로 바로가기
728x90
반응형

목차

     

    개요

    이번 글의 주제는 지난번 글에서 기재한 내용 중 일부를 이용해 FastAPI에서 테스트 코드 작성 시에 dependency-injector를 통해 이를 조정할 수 있게 만드는 방법을 기록한다.

     

    1. app.py를 사용 시 외부환경 고려하기

    지난 글에서 사용한 app.py는 다음과 같이 생긴 코드이다.

    # app.py
    from fastapi import FastAPI
    from src.config import setup
    
    class FastApi:
        def __init__(self, app):
            self.app = app
    
        def __call__(self, *args, **kwargs):
            setup.router(self.app)
            setup.container()
    
            return self.app
    
    
    server = FastApi(app=FastAPI())

    그런데 이는 FastAPI가 시작될 때 지극히도 내부에 설정된 환경을 기반으로 동작한다는 것에 문제가 있다. 이에 대한 문제 사례 중 하나는 TestClient를 사용할 때이다.

     

    2. FastAPI의 TestClient

    FastAPI의 TestClient는 다음과 같은 형태로 사용할 수 있다.

    from fastapi.testclient import TestClient
    from src.adapters.repository import exceptions
    from src.main import app
    import pytest
    
    from src.libraries.utils import token
    
    client = TestClient(app)
    
    
    def test_case01():
        response = client.post(
            '/api',
            data={"key1": "va1"}
    	)
        
        assert response.status_code == 200

    TestClient라는 객체에 FastAPI 인스턴스를 넘겨줌으로써 사용할 수 있다. 손쉽게 사용할 수 있지만 앞에서 작성해 놓은 app.py를 그대로 이용하게 될 경우 Test 환경으로 전환을 하지 못한다

     

    3. dependency-injector를 이용하여 관리하기

    DataBase 연결에 대한 정보를 관리하기 위해서 class를 추상화하여 사용하는 방법도 있지만 필자는 dependency-injector를 사용 중이었기에 dependency-injector에서 외부로터 데이터를 받아 사용할 수 있는 방법이 필요했다. 필자가 찾은 방법은 config provider를 이용하는 것이었다.  

     

    3.1 dependency-injector의 Configuration 프로바이더

    dependency-injector는 의 Configuration 프로바이더는 다음과 같이 사용한다.

    from __future__ import annotations
    
    from dependency_injector import containers, providers
    
    class DataBaseConfig(containers.DeclarativeContainer):
        config = providers.Configuration()

    Container안에 providers.Configuation()을 정의한다. 이렇게 정의를 하고 나면 아래와 같은 방식으로 외부에서 값을 설정할 수 있게 된다.

    # Container Instance를 선언하고 값 설정
    database_config = database.DataBaseConfig()
    session_container.config.from_dict({
        'drivername': "DRIVER_NAME",
        'username': "USERNAME",
        'password': "PASSWORD",
        'database': "DATABASE",
        'host': "HOST",
        'port': "PORT"
    })

    다시 DataBaseConfig Container 안에서 선언해 둔 config를 외부에서 설정한 속성을 이용할 수 있게 된다.

    class DataBaseContainer(containers.DeclarativeContainer):
        config = providers.Configuration()
    	
        session = providers.Singleton(	
            SqlAlchemySessionFactory.get_session,
            drivername=config.drivername,
            username=config.username,
            password=config.password,
            database=config.database,
            host=config.host,
            port=config.port
        )

     

    4. Test 환경으로 전환점 만들기

    다시 돌아와서 app.py의 내용을 다음과 같이 고치도록 하자.

    # app.py
    from fastapi import FastAPI
    from src.config import setup
    
    DATABASE_CONFIG = {
        "drivername" : "",
        "host": "",
        "port" : 1234,
        "database" : "",
        "username" : "",
        "password" :""   
    }
    
    class FastApi:
        def __init__(self, app, database):
            self.app = app
            self.database = database
    
        def __call__(self, *args, **kwargs):
            setup.router(self.app)
            setup.container(self.database)
    
            return self.app
    
    
    server = FastApi(app=FastAPI(), database=DATABASE_CONFIG)

    위와 같이 선언하면 TestClient를 이용할 때 다음과 같이 사용할 수 있게 된다.

    from fastapi.testclient import TestClient
    from src.adapters.repository import exceptions
    from src.main import app
    import pytest
    
    from src.libraries.utils import token
    
    app = FastApi(app=FastAPI(), database=TEST_DATABASE)
    
    client = TestClient(app)
    
    
    def test_case01():
        response = client.post(
            '/api',
            data={"key1": "va1"}
    	)
        
        assert response.status_code == 200

     

    728x90
    반응형