Browse Source

🐛 Fix AssertionError when using TestClient directly with APIRouter (#14128)

pull/15141/head
Niler Barcelos 4 months ago
parent
commit
38786d1905
  1. 5
      fastapi/routing.py
  2. 62
      tests/test_router_direct_testclient.py

5
fastapi/routing.py

@ -115,6 +115,11 @@ def request_response(
response_awaited = False
async with AsyncExitStack() as request_stack:
scope["fastapi_inner_astack"] = request_stack
# Ensure fastapi_middleware_astack exists in scope even when
# the router is used directly without a FastAPI app (which
# normally sets it up via AsyncExitStackMiddleware).
if "fastapi_middleware_astack" not in scope:
scope["fastapi_middleware_astack"] = request_stack
async with AsyncExitStack() as function_stack:
scope["fastapi_function_astack"] = function_stack
response = await f(request)

62
tests/test_router_direct_testclient.py

@ -0,0 +1,62 @@
"""Test for issue #14128: Router used directly with TestClient and yield dependencies."""
from fastapi import APIRouter, Depends
from fastapi.testclient import TestClient
def test_router_direct_testclient_with_yield_dependency():
"""TestClient(router) should work even without wrapping in FastAPI()."""
router = APIRouter()
async def yield_dep():
yield "value"
@router.get("/test")
async def endpoint(dep: str = Depends(yield_dep)):
return {"dep": dep}
client = TestClient(router)
response = client.get("/test")
assert response.status_code == 200
assert response.json() == {"dep": "value"}
def test_router_direct_testclient_with_multiple_yield_dependencies():
"""Multiple yield dependencies should work with direct router TestClient."""
router = APIRouter()
async def dep_a():
yield "a"
async def dep_b():
yield "b"
@router.get("/test")
async def endpoint(a: str = Depends(dep_a), b: str = Depends(dep_b)):
return {"a": a, "b": b}
client = TestClient(router)
response = client.get("/test")
assert response.status_code == 200
assert response.json() == {"a": "a", "b": "b"}
def test_router_direct_testclient_yield_dependency_cleanup():
"""Yield dependency cleanup should run even with direct router TestClient."""
cleaned_up = False
router = APIRouter()
async def yield_dep():
nonlocal cleaned_up
yield "value"
cleaned_up = True
@router.get("/test")
async def endpoint(dep: str = Depends(yield_dep)):
return {"dep": dep}
client = TestClient(router)
response = client.get("/test")
assert response.status_code == 200
assert cleaned_up
Loading…
Cancel
Save