From 0ab0d2ae8027fcea557beaa1c9b60ec12db44f81 Mon Sep 17 00:00:00 2001 From: Shin Date: Sat, 7 Feb 2026 03:30:42 +0000 Subject: [PATCH] fix(tests): Fix sendgrid email tests to properly mock httpx client The tests were potentially hitting the real SendGrid API because the mock was patching get_async_httpx_client() but the actual client could be cached or the mock timing could be off. Fix by directly replacing logger.async_httpx_client after instantiation, which guarantees the mock is used regardless of caching or initialization timing issues. Changes: - Replace mock_httpx_client fixture with simpler mock_async_client fixture - Directly inject mock client into logger instance after creation - Remove respx decorator (no longer needed with direct injection) - Simplify test structure while maintaining same assertions --- .../send_emails/test_sendgrid_email.py | 56 ++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_sendgrid_email.py b/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_sendgrid_email.py index fb070cf19b8..21ffae2032d 100644 --- a/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_sendgrid_email.py +++ b/tests/test_litellm/enterprise/enterprise_callbacks/send_emails/test_sendgrid_email.py @@ -54,26 +54,27 @@ def mock_env_vars(): @pytest.fixture -def mock_httpx_client(): - with mock.patch( - "litellm_enterprise.enterprise_callbacks.send_emails.sendgrid_email.get_async_httpx_client" - ) as mock_client: +def mock_async_client(): + """ + Create a mock async httpx client that can be injected directly + into the logger instance, bypassing any caching issues. + """ + mock_response = mock.Mock(spec=Response) + mock_response.status_code = 202 + mock_response.text = "accepted" + mock_response.raise_for_status.return_value = None - mock_response = mock.Mock(spec=Response) - mock_response.status_code = 202 - mock_response.text = "accepted" - 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 + mock_client = mock.AsyncMock() + mock_client.post.return_value = mock_response + return mock_client @pytest.mark.asyncio -async def test_send_email_success(mock_env_vars, mock_httpx_client): +async def test_send_email_success(mock_env_vars, mock_async_client): logger = SendGridEmailLogger() + # Directly replace the httpx client to ensure the mock is used + # This bypasses any caching or initialization timing issues + logger.async_httpx_client = mock_async_client from_email = "test@example.com" to_email = ["recipient@example.com"] @@ -84,8 +85,8 @@ async def test_send_email_success(mock_env_vars, mock_httpx_client): from_email=from_email, to_email=to_email, subject=subject, html_body=html_body ) - 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 assert call_args[1]["url"] == "https://api.sendgrid.com/v3/mail/send" payload = call_args[1]["json"] @@ -118,32 +119,23 @@ 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.sendgrid.com/v3/mail/send").mock( - return_value=httpx.Response(202, text="accepted") - ) - +async def test_send_email_multiple_recipients(mock_env_vars, mock_async_client): logger = SendGridEmailLogger() + # Directly replace the httpx client to ensure the mock is used + # This bypasses any caching or initialization timing issues + logger.async_httpx_client = mock_async_client from_email = "test@example.com" to_email = ["recipient1@example.com", "recipient2@example.com"] subject = "Test Subject" html_body = "

Test email body

" - mock_response = mock.Mock(spec=Response) - mock_response.status_code = 202 - mock_response.text = "accepted" - mock_response.raise_for_status.return_value = None - mock_httpx_client.post.return_value = mock_response - await logger.send_email( from_email=from_email, to_email=to_email, subject=subject, html_body=html_body ) - mock_httpx_client.post.assert_called_once() - payload = mock_httpx_client.post.call_args[1]["json"] + mock_async_client.post.assert_called_once() + payload = mock_async_client.post.call_args[1]["json"] assert payload["personalizations"][0]["to"] == [ {"email": "recipient1@example.com"},