I have a problem with testing endpoints that use both Depends
AND Security
. First of all, here is my root endpoint which i can test perfectly fine using app.dependency_override
:
# restapi/main.py
from api_v1.api import router as api_router
from authentication.verification import Verification
from fastapi import FastAPI, Security
from mangum import Mangum
app = FastAPI()
security = Verification()
@app.get("/")
async def root(auth_result: str = Security(security.verify)):
return {"message": "Hello World this is restapi.py!"}
app.include_router(api_router, prefix="/api/v1")
handler = Mangum(app)
And then to test it:
from fastapi.testclient import TestClient
from restapi.main import app, security
def test_root_api():
client = TestClient(app=app)
app.dependency_overrides[security.verify] = lambda: ""
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World this is restapi.py!"}
app.dependency_overrides = {}
def test_root_api_without_security():
client = TestClient(app=app)
response = client.get("/")
assert response.status_code == 403
assert response.json() == {"detail": "Not authenticated"}
There are no problems when I only use the Security
function. However I have another endpoint (that i define as api/v1/exchange_rates
in my api_router) which has both Depends
and Security
:
# restapi/api_v1/endpoints/exchange_rates.py
security = Verification()
router = APIRouter()
@router.get("/")
async def exchange_rates(
query: ExchangeRatesQuery = Depends(),
auth_result: str = Security(security.verify),
):
The ExchangeRatesQuery
is a pydantic BaseModel. The test below for this endpoint works perfectly fine ONLY if I remove the auth_result: str = Security...
from my endpoint.
from restapi.main import app
from restapi.api_v1.endpoints.exchange_rates import security
def test_exchange_rates():
client = TestClient(app=app)
app.dependency_overrides[security.verify] = lambda: ""
response = client.get(
"/api/v1/exchange-rates?start_date=2023-03-20&end_date=2023-03-21&base_currency=USD&target_currencies=EUR",
)
assert response.status_code == 200
assert response.json() == [
{
"exchange_date": "2023-03-20",
"exchange_rate": "0.88",
"base_currency": "USD",
"target_currency": "EUR",
}
]
app.dependency_overrides = {}
Even though I import security
from my exchange_rates.py
to ensure that I'm overriding the dependencies of the correct object, this doesn't seem to work. Any help is greatly appreciated.
Edit 1
I've also tried patching the verify function with a standard return value of ""
using unittest.mock, but have not been able to make it work that way either.
@mock.patch.object(Verification, "verify", lambda: "") # also tried security instead of Verification
def test_exchange_rates()
...
app.dependency_overrides
works by using the actual function instance as a key - i.e. the exact function instance that gets passed to Security
or Depends
.
If these functions are not the same - either because they're registered to different instances or that they're being dynamically generated (for example by returning a function defined inside another function - usually as a closure), the dependency will not be overriden (since FastAPI has no way of knowing what function to replace the other one with).
Make sure they're actually the same instance and same function. If you attach debug breakpoints inside the function / method being called, you should be able to see if they're the same as you expect them to be (for example by looking at self
or the function being returned).