I am writing a unit test for the following FastAPI endpoint:
from fastapi import APIRouter, HTTPException, Depends, Request
from fastapi_cognito import CognitoToken
from app.config.cognito import cognito
from app.user_management import service as user_management_service
api = APIRouter(prefix="/account")
@api.put('/change-password')
def change_password(
req: Request,
request: ChangePasswordRequest,
user: CognitoToken = Depends(cognito.auth_required),
):
try:
token = req.headers["Authorization"].split('Bearer ')[1]
user_management_service.change_password(
old_password=request.old_password,
new_password=request.new_password,
access_token=token
)
return ChangePasswordResponse(detail="Password changed")
except user_management_service.NotAuthorizedException:
raise HTTPException(401, NotAuthorizedResponse().detail)
except user_management_service.LimitExceededException:
raise HTTPException(429, LimitExceededResponse().detail)
I am trying to mock req: Request
in my unit test, but I keep running into this error:
self = Headers({'host': 'testserver', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'user-agent': 'testclient', 'content-length': '64', 'content-type': 'application/json'})
key = 'Authorization'
def __getitem__(self, key: str) -> str:
get_header_key = key.lower().encode("latin-1")
for header_key, header_value in self._list:
if header_key == get_header_key:
return header_value.decode("latin-1")
> raise KeyError(key)
E KeyError: 'Authorization'
/usr/local/lib/python3.12/site-packages/starlette/datastructures.py:539: KeyError
It seems like pytest cannot recognize req when it is not properly initialized as an instance before calling the endpoint?
How should I correctly mock req: Request
to include headers only Authorization in unit test?
I am writing a unit test for the following FastAPI endpoint:
from fastapi import APIRouter, HTTPException, Depends, Request
from fastapi_cognito import CognitoToken
from app.config.cognito import cognito
from app.user_management import service as user_management_service
api = APIRouter(prefix="/account")
@api.put('/change-password')
def change_password(
req: Request,
request: ChangePasswordRequest,
user: CognitoToken = Depends(cognito.auth_required),
):
try:
token = req.headers["Authorization"].split('Bearer ')[1]
user_management_service.change_password(
old_password=request.old_password,
new_password=request.new_password,
access_token=token
)
return ChangePasswordResponse(detail="Password changed")
except user_management_service.NotAuthorizedException:
raise HTTPException(401, NotAuthorizedResponse().detail)
except user_management_service.LimitExceededException:
raise HTTPException(429, LimitExceededResponse().detail)
I am trying to mock req: Request
in my unit test, but I keep running into this error:
self = Headers({'host': 'testserver', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'user-agent': 'testclient', 'content-length': '64', 'content-type': 'application/json'})
key = 'Authorization'
def __getitem__(self, key: str) -> str:
get_header_key = key.lower().encode("latin-1")
for header_key, header_value in self._list:
if header_key == get_header_key:
return header_value.decode("latin-1")
> raise KeyError(key)
E KeyError: 'Authorization'
/usr/local/lib/python3.12/site-packages/starlette/datastructures.py:539: KeyError
It seems like pytest cannot recognize req when it is not properly initialized as an instance before calling the endpoint?
How should I correctly mock req: Request
to include headers only Authorization in unit test?
1 Answer
Reset to default 0Because the error message showed something like Header({....'user-agent': 'test-client'...})
, I assume you are using TestClient
to test the path operation (PUT - /account/change-password).
Also, since the error message showed KeyError: 'Authorization'
, I think your request is not properly initialized with the Authorization header.
If you are actually using TestClient
for testing, make sure to include the Authorization
header in your test code, since your path operation logic (or possibly your Cognito dependency) requires that header.
Below is an example of how to include the Authorization
header in your TestClient
request:
response = client.put(
"/account/change-password",
json={"old_password": "old", "new_password": "new"},
headers={"Authorization": "Bearer <your_token_here>"}
)
Request
instead of setting up the request properly to match the expected request in your test? (a secondary point: don't use bothreq
andrequest
as variable names in the same functions - you'll get confused very fast and introduce subtle bugs. Userequest
as the name forRequest
as that's convention, and instead name your request body according to what it actually represents (for examplechange_password
or something similar). – MatsLindh Commented Feb 18 at 9:18