From 0a313efa9a08bb44eb47c00eb49c457c9fd505af Mon Sep 17 00:00:00 2001 From: shin-bot-litellm Date: Sun, 1 Feb 2026 01:27:59 +0000 Subject: [PATCH] fix(test_resend_email): use direct mock injection for all email tests Extend the mock injection pattern used in test_send_email_missing_api_key to all other tests in the file: - test_send_email_success - test_send_email_multiple_recipients Instead of relying on fixture-based patching and respx mocks which can fail due to import order and caching issues, directly inject the mock HTTP client into the logger instance. This ensures mocks are always used regardless of test execution order. --- .../send_emails/test_resend_email.py | 75 +++++++------------ 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_resend_email.py b/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_resend_email.py index 87f62cf4468..b07216921eb 100644 --- a/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_resend_email.py +++ b/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_resend_email.py @@ -2,9 +2,7 @@ import os import sys import unittest.mock as mock -import httpx import pytest -import respx from httpx import Response sys.path.insert(0, os.path.abspath("../../..")) @@ -38,32 +36,8 @@ def mock_env_vars(): yield -@pytest.fixture -def mock_httpx_client(): - with mock.patch( - "litellm_enterprise.enterprise_callbacks.send_emails.resend_email.get_async_httpx_client" - ) as mock_client: - - mock_response = mock.Mock(spec=Response) - mock_response.status_code = 200 - mock_response.json.return_value = {"id": "test_email_id"} - mock_response.raise_for_status.return_value = None - - mock_async_client = mock.AsyncMock() - mock_async_client.post.return_value = mock_response - - mock_client.return_value = mock_async_client - yield mock_async_client - - @pytest.mark.asyncio -@respx.mock -async def test_send_email_success(mock_env_vars, mock_httpx_client): - # Block all HTTP requests at network level to prevent real API calls - respx.post("https://api.resend.com/emails").mock( - return_value=httpx.Response(200, json={"id": "test_email_id"}) - ) - +async def test_send_email_success(mock_env_vars): # Initialize the logger logger = ResendEmailLogger() @@ -73,14 +47,27 @@ async def test_send_email_success(mock_env_vars, mock_httpx_client): subject = "Test Subject" html_body = "

Test email body

" + # Create mock HTTP client and inject it directly into the logger + # This ensures the mock is used regardless of any caching/import issues + mock_response = mock.Mock(spec=Response) + mock_response.status_code = 200 + mock_response.json.return_value = {"id": "test_email_id"} + mock_response.raise_for_status.return_value = None + + mock_async_client = mock.AsyncMock() + mock_async_client.post.return_value = mock_response + + # Directly inject the mock client to bypass any caching + logger.async_httpx_client = mock_async_client + # Send email await logger.send_email( from_email=from_email, to_email=to_email, subject=subject, html_body=html_body ) # Verify the HTTP client was called correctly - mock_httpx_client.post.assert_called_once() - call_args = mock_httpx_client.post.call_args + mock_async_client.post.assert_called_once() + call_args = mock_async_client.post.call_args # Verify the URL assert call_args[1]["url"] == "https://api.resend.com/emails" @@ -97,13 +84,7 @@ async def test_send_email_success(mock_env_vars, mock_httpx_client): @pytest.mark.asyncio -@respx.mock async def test_send_email_missing_api_key(): - # Block all HTTP requests at network level to prevent real API calls - respx.post("https://api.resend.com/emails").mock( - return_value=httpx.Response(200, json={"id": "test_email_id"}) - ) - # Remove the API key from environment before initializing logger original_key = os.environ.pop("RESEND_API_KEY", None) @@ -146,13 +127,7 @@ async def test_send_email_missing_api_key(): @pytest.mark.asyncio -@respx.mock -async def test_send_email_multiple_recipients(mock_env_vars, mock_httpx_client): - # Block all HTTP requests at network level to prevent real API calls - respx.post("https://api.resend.com/emails").mock( - return_value=httpx.Response(200, json={"id": "test_email_id"}) - ) - +async def test_send_email_multiple_recipients(mock_env_vars): # Initialize the logger logger = ResendEmailLogger() @@ -162,13 +137,17 @@ async def test_send_email_multiple_recipients(mock_env_vars, mock_httpx_client): subject = "Test Subject" html_body = "

Test email body

" - # Mock the response to avoid making real HTTP requests + # Create mock HTTP client and inject it directly into the logger mock_response = mock.Mock(spec=Response) - mock_response.raise_for_status.return_value = None - mock_response.status_code = 200 mock_response.json.return_value = {"id": "test_email_id"} - mock_httpx_client.post.return_value = mock_response + mock_response.raise_for_status.return_value = None + + mock_async_client = mock.AsyncMock() + mock_async_client.post.return_value = mock_response + + # Directly inject the mock client to bypass any caching + logger.async_httpx_client = mock_async_client # Send email await logger.send_email( @@ -176,7 +155,7 @@ async def test_send_email_multiple_recipients(mock_env_vars, mock_httpx_client): ) # Verify the HTTP client was called with multiple recipients - mock_httpx_client.post.assert_called_once() - call_args = mock_httpx_client.post.call_args + mock_async_client.post.assert_called_once() + call_args = mock_async_client.post.call_args request_body = call_args[1]["json"] assert request_body["to"] == to_email