pytest에서 dependency injection 관련 depends mocking이 안되는 문제 발생 이거 fastapi app 단에서 depends를 resolve 해주는거라 내가 따로 unittest를 작성하면 depends가 제대로 작동을 안한다. → pytest fixture를 사용해서 미리 depends할 애들을 만들어주고, override하는 방법을 사용하기로 결정 내부적으로 db에서 async_scoped_session을 사용하기 때문에 scope_func로 uuid4 형태의 contextvar를 사용하고 있었음. 근데 fixture에서 제대로 설정돼도 실제 테스트 pytest.mark.asyncio가 시작되면 contextvar가 설정이 풀려있는 문제가 발생 https://github.com/pytest-dev/pytest-asyncio/issues/127 → 알고보니 파이썬 3.10에서는 pytest asyncio가 독립적인 task로 실행돼서 context를 잃어버린다고 한다. → contextvar를 만들때 쓰는 uuid만 fixture로 고정하고 그때그때 테스트에서 contextvar를 새로 만들어주는 방법으로 해결

pytest debug로 돌릴때 결과만 나오는거 → test results 말고 debug console을 보면 된다. extension 깔려 있어서 자동으로 됨

 
@pytest.fixture(scope="session")
def event_loop():
    loop = asyncio.get_event_loop_policy().new_event_loop()
    yield loop
    loop.close()
 
@pytest.fixture(scope="function")
def config() -> Generator[Settings, None, None]:
    config = get_settings()
    yield config
 
@pytest.fixture(scope="session")
def context_session_id():
    context_session_id = str(uuid4())
    context_token = set_session_context(context_session_id)
    yield context_session_id
    reset_session_context(context_token)
 
@pytest.fixture(scope="function")
async def db_session(context_session_id):
    config = get_settings()
    engine = create_async_engine(
        "{DB_URL}://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}".format(
            DB_URL="postgresql+asyncpg",
            DB_USER=config.POSTGRES_USER,
            DB_PASSWORD=config.POSTGRES_PASSWORD,
            DB_HOST=config.DB_HOST,
            DB_PORT=config.DB_PORT,
            DB_NAME=config.POSTGRES_DB,
        ),
        pool_recycle=3600,
    )
    set_session_context(context_session_id)
    session_factory=async_sessionmaker(bind=engine, expire_on_commit=False, class_=AsyncSession)
    db_session = async_scoped_session(
        session_factory=session_factory, scopefunc=get_session_context
    )
    yield db_session
    await db_session.close()
    await db_session.remove()
    await engine.dispose()
 
 
async def user_service(db_session: AsyncSession, config: Settings, context_session_id: str) -> AsyncGenerator[UserService, Any]:
    user_repository = UserRepository(session=db_session)
    config = config
    yield UserService(user_repository, config)
 
@pytest.mark.asyncio
@sessionmanager
async def test_get_user_name(user_service, context_session_id):
    username = await user_service.get_user_name("8a42b8cf-63fe-4f0e-b8ce-78bb2da93c18")
    assert username == "nj_jeong"
 

이렇게 해서 해결 완료

session bug

transactional 데코레이터에서 session을 닫으면 제대로 풀에 반환이 안되는 문제가 있었던 것 같음. 명시적으로 yield session을 한 곳에서 닫아주는거 추가.