fix(tests): use dependency_overrides for get_task_executor, not patch()
FastAPI resolves Depends(get_task_executor) against the function object it
captured when each route was decorated, at import time. patch('src.main.
get_task_executor') therefore never reaches an already-registered route —
confirmed empirically with a minimal FastAPI app before touching this repo's
tests. Every one of these tests fell through to the real dependency, which
called the real psycopg2.connect() and failed on postgres-shared's DNS (a
Docker-network name unreachable from a host process either way, so this
reproduced identically with and without host networking).
app.dependency_overrides is FastAPI's own supported mechanism for this, and
was already used correctly elsewhere in this suite (test_task_delete.py).
Added a shared override_task_executor fixture in conftest.py and switched
every get_task_executor patch() call site in test_api_comprehensive.py to it.
Source (src/main.py) is unchanged — Depends() is the idiomatic, correct
pattern; the tests were using an ineffective substitute for it.
This commit is contained in:
+17
-1
@@ -20,7 +20,7 @@ os.environ["GITEA_USER"] = "test-librarian"
|
||||
os.environ["GITEA_PASSWORD"] = "test-gitea-token"
|
||||
os.environ["REDIS_HOST"] = "redis-shared"
|
||||
|
||||
from src.main import app
|
||||
from src.main import app, get_task_executor
|
||||
from src.config import Settings, get_settings
|
||||
|
||||
|
||||
@@ -44,6 +44,22 @@ def auth_headers(api_key: str) -> dict:
|
||||
return {"Authorization": f"Bearer {api_key}"}
|
||||
|
||||
|
||||
# FastAPI resolves `Depends(get_task_executor)` against the function object it
|
||||
# captured when each route was decorated, at import time. `unittest.mock.patch`
|
||||
# on the module attribute `src.main.get_task_executor` therefore never reaches
|
||||
# an already-registered route — the route keeps calling the original function.
|
||||
# `app.dependency_overrides` is FastAPI's own supported mechanism for this
|
||||
# (already used correctly in test_task_delete.py); this fixture centralizes it
|
||||
# so call sites just need the executor mock they want installed.
|
||||
@pytest.fixture
|
||||
def override_task_executor() -> Generator[MagicMock, None, None]:
|
||||
"""Install a mock TaskExecutor as the live dependency for this test only."""
|
||||
mock_executor = MagicMock()
|
||||
app.dependency_overrides[get_task_executor] = lambda: mock_executor
|
||||
yield mock_executor
|
||||
app.dependency_overrides.pop(get_task_executor, None)
|
||||
|
||||
|
||||
# Synchronous test client
|
||||
@pytest.fixture
|
||||
def client() -> Generator[TestClient, None, None]:
|
||||
|
||||
Reference in New Issue
Block a user