In my get_orders.py
file I am importing a function called admin_only
that exists at the given path (src.lib.authorization
). In my test_get_orders.py
file I am trying to patch this function, however the function is not getting patched and when running pytest, it attempts to call the function's underlying code instead of returning True. Why is this the case and how can I fix this? It's also important to mention that get_orders.py
is defined at the following path src/routes/get_orders.py
# get_orders.py
import boto3
import os
from fastapi import APIRouter, Depends
from aws_lambda_powertools import Logger
from fastapi.exceptions import HTTPException
from src.models import Order
from src.lib.dynamodb import DynamoConnection
from src.lib.response import fastapi_gateway_response
from src.lib.authorization import admin_only
logger = Logger()
router = APIRouter()
orders_table = DynamoConnection(
os.environ.get("DYNAMODB_REGION", "us-east-1"),
os.environ.get("DYNAMODB_ENDPOINT_URL", None),
os.environ.get("DYNAMODB_ORDERS_TABLE_NAME", "orders"),
).table
@logger.inject_lambda_context
@router.get(
"/orders",
status_code=200,
dependencies=[Depends(admin_only)],
)
def get_orders():
logger.info(f"Getting orders")
dynamo_response = orders_table.scan()
if "Items" not in dynamo_response:
raise HTTPException(status_code=404, detail="No orders found")
orders = [Order(**o).clean() for o in dynamo_response.get("Items")]
logger.info(f"Returning {len(orders)} orders")
return fastapi_gateway_response(200, {}, orders)
#test_get_orders.py
import pytest
import logging
from unittest.mock import patch
from freezegun import freeze_time
from botocore.stub import Stubber
from fastapi.testclient import TestClient
from src.api import app
from src.routes.get_orders import orders_table
logger = logging.getLogger()
test_client = TestClient(app, headers={"Authorization": "Bearer TOKEN"})
@pytest.fixture(autouse=True, scope="function")
def orders_dynamodb_stub():
with Stubber(orders_table.meta.client) as ddb_stubber:
yield ddb_stubber
ddb_stubber.assert_no_pending_responses()
@freeze_time("2024-03-22 12:00:00")
@patch("src.routes.get_orders.admin_only", return_value=True)
def test_handler_valid_event_get_orders(orders_dynamodb_stub):
orders_dynamodb_stub.add_response(
"scan",
{
"Items": [
{
"order_id": {"S": "ORDER-1"},
"dessert_id": {"S": "DESSERT-1"},
"dessert_name": {"S": "Chocolate Cake"},
"quantity": {"N": "1"},
"customer_first_name": {"S": "jane"},
"customer_last_name": {"S": "doe"},
"customer_email": {"S": "jane.doe@gmail.com"},
"customer_phone_number": {"S": "555-555-5555"},
"customer_zip_code": {"S": "90210"},
"delivery_address": {"S": "123 Main St, Los Angeles, CA 90210"},
"scheduled_delivery_time": {"N": "1711108800"},
"order_total": {"N": "10.00"},
"order_status": {"S": "NEW"},
"order_date": {"N": "1711108800"},
},
],
},
expected_params={"TableName": "orders"},
)
response = test_client.get("/v1/orders")
pytest.helpers.assert_responses_equal(
response,
200,
[
{
"order_id": "ORDER-1",
"dessert_id": "DESSERT-1",
"dessert_name": "Chocolate Cake",
"quantity": 1,
"customer_first_name": "jane",
"customer_last_name": "doe",
"customer_email": "jane.doe@gmail.com",
"customer_phone_number": "555-555-5555",
"customer_zip_code": "90210",
"delivery_address": "123 Main St, Los Angeles, CA 90210",
"scheduled_delivery_time": 1711108800,
"order_total": 10.00,
"order_status": "NEW",
"order_date": 1711108800,
}
],
)
Since admin_only
is used in a dependency, the reference is passed when initiating the module, meaning patching it won’t do anything. The solution here is to use FastAPI's dependency overrides. Something like this:
@freeze_time("2024-03-22 12:00:00")
def test_handler_valid_event_get_orders(orders_dynamodb_stub):
app.dependency_overrides[admin_only] = lambda *args, **kargs: True)
# Run your test
app.dependency_overrides = {}