테스트 환경
개발환경
python==3.9 async-asgi-testclient==1.4.11 pytest==8.1.1 pytest-asyncio==0.23.6
디렉토리 구조├── alembic ├── frontend ├── scripts ├── src │ ├── domains │ ├── external_service │ ├── main.py ├── tests │ ├── conftest.py │ └── src └── venv
상황
FastAPI를 활용한 동기 API 단위 테스트를 작성하던 중 정의한 fixture를 찾을 수 없다는 문제에 직면했다. 나는 conftest.py에 sync_client를 정의한 상태였는데, 해당 fixture를 찾아오지 못했다.
이와 관련하여, 나는 conftest.py의 선언된 코드의 문제라고 생각했다. 하지만 다양한 pytest 예시 자료를 참고해도, 잘못된 부분을 찾을 수 없었다.
조치 사항
문제의 원인을 고민하던 중 에러 메시지를 해결하자 라는 생각으로, "해당 fixture를 import 해보자." 하는 아이디어로, 아래의 코드를 추가하여, 발생한 문제를 해결했다.
추가한 코드
from tests.conftest import sync_client, sync_session
- sync_client 만 import 할 경우, sync_client 에서 사용하는 sync_session을 찾지못하는 문제가 발생했다.
- sync_client에서 사용하는 sync_session 까지 모두 import 선언을 해야 테스트가 정상적으로 실행 된다.
결론
찾지 못하는 fixture에 대하여, 직접 명시해줌으로써 문제를 해결할 수 있었다. 그러나 이것이 근본적인 문제의 원인을 해결한 것인 아닌 것 같다.
- import 코드는 왜 사용되고 있다고 인식 되지 않는가?(IDE 문제인가? 아니면 코드 상의 문제인가?)
- 다른 예시들과는 다르게 왜 내 환경에서는 fixture를 찾지 못하는가?
예상되는 문제의 원인은 파일 디렉토리 구조 때문인듯한데, 디렉토리 구조가 파이썬의 Import에 어떤 영향을 주는지에 대해서는 아직 내가 잘 모른 상태이다. 하지만 무엇보다 내가 아직 pytest에 익숙하지 않아 이런 이슈를 겪고 있는듯하여, 공식문서를 참고하며 다양한 테스트를 작성하면서, pytest에 익숙해 져야겠다.
테스트에 사용한 코드
#test_sync_example.py from src.domains.sync_example.database.models import SyncExample from tests.conftest import sync_client, sync_session def test_sync_example_생성(sync_client): res = sync_client.post("/api/sync/no-login/sync/example", json={"name": "test1", "description": "test"}) new_sync_example = SyncExample(**res.json()) assert res.status_code == 201 assert new_sync_example.name == "test1"
# conftest.py import pytest from starlette.testclient import TestClient from src.database import Base, get_db from src.main import app from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker SYNC_SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:test@localhost:3306/fastapi_test" # sync_engine = create_engine(SYNC_SQLALCHEMY_DATABASE_URL, echo=True) sync_engine = create_engine(SYNC_SQLALCHEMY_DATABASE_URL) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=sync_engine) @pytest.fixture def sync_session(): Base.metadata.drop_all(bind=sync_engine) Base.metadata.create_all(bind=sync_engine) db = TestingSessionLocal() try: yield db finally: db.close() @pytest.fixture def sync_client(sync_session): def override_get_db(): try: yield sync_session finally: sync_session.close() # app에서 사용하는 DB를 오버라이드하는 부분 app.dependency_overrides[get_db] = override_get_db yield TestClient(app)
728x90
'개인공부 > 트러블슈팅' 카테고리의 다른 글
[ Trouble-Shooting ] 컨테이너 간 통신에서 발생한 Failed to send HTTP request to endpoint (0) | 2023.10.26 |
---|