Python: Integration tests for Azure AI client and fixes in samples (#2387)

* Added integration tests

* Update python/packages/azure-ai/tests/test_azure_ai_client.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Small fixes in samples

* Small fix

* Small fix

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Dmytro Struk
2025-11-21 16:31:57 -08:00
committed by GitHub
Unverified
parent b7a19b0fa2
commit ee8936d514
6 changed files with 116 additions and 15 deletions
@@ -1,9 +1,16 @@
# Copyright (c) Microsoft. All rights reserved.
import os
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from typing import Annotated
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
ChatAgent,
ChatClientProtocol,
ChatMessage,
ChatOptions,
@@ -11,15 +18,50 @@ from agent_framework import (
TextContent,
)
from agent_framework.exceptions import ServiceInitializationError
from azure.ai.projects.aio import AIProjectClient
from azure.ai.projects.models import (
ResponseTextFormatConfigurationJsonSchema,
)
from azure.identity.aio import AzureCliCredential
from openai.types.responses.parsed_response import ParsedResponse
from openai.types.responses.response import Response as OpenAIResponse
from pydantic import BaseModel, ConfigDict, ValidationError
from pydantic import BaseModel, ConfigDict, Field, ValidationError
from agent_framework_azure_ai import AzureAIClient, AzureAISettings
skip_if_azure_ai_integration_tests_disabled = pytest.mark.skipif(
os.getenv("RUN_INTEGRATION_TESTS", "false").lower() != "true"
or os.getenv("AZURE_AI_PROJECT_ENDPOINT", "") in ("", "https://test-project.cognitiveservices.azure.com/")
or os.getenv("AZURE_AI_MODEL_DEPLOYMENT_NAME", "") == "",
reason=(
"No real AZURE_AI_PROJECT_ENDPOINT or AZURE_AI_MODEL_DEPLOYMENT_NAME provided; skipping integration tests."
if os.getenv("RUN_INTEGRATION_TESTS", "false").lower() == "true"
else "Integration tests are disabled."
),
)
@asynccontextmanager
async def temporary_chat_client(agent_name: str) -> AsyncIterator[AzureAIClient]:
"""Async context manager that creates an Azure AI agent and yields an `AzureAIClient`.
The underlying agent version is cleaned up automatically after use.
Tests can construct their own `ChatAgent` instances from the yielded client.
"""
endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=endpoint, credential=credential) as project_client,
):
chat_client = AzureAIClient(
project_client=project_client,
agent_name=agent_name,
)
try:
yield chat_client
finally:
await project_client.agents.delete(agent_name=agent_name)
def create_test_azure_ai_client(
mock_project_client: MagicMock,
@@ -751,3 +793,64 @@ def mock_project_client() -> MagicMock:
mock_client.close = AsyncMock()
return mock_client
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
return f"The weather in {location} is sunny with a high of 25°C."
@pytest.mark.flaky
@skip_if_azure_ai_integration_tests_disabled
async def test_azure_ai_chat_client_agent_basic_run() -> None:
"""Test ChatAgent basic run functionality with AzureAIClient."""
async with (
temporary_chat_client(agent_name="BasicRunAgent") as chat_client,
ChatAgent(chat_client=chat_client) as agent,
):
response = await agent.run("Hello! Please respond with 'Hello World' exactly.")
# Validate response
assert isinstance(response, AgentRunResponse)
assert response.text is not None
assert len(response.text) > 0
assert "Hello World" in response.text
@pytest.mark.flaky
@skip_if_azure_ai_integration_tests_disabled
async def test_azure_ai_chat_client_agent_basic_run_streaming() -> None:
"""Test ChatAgent basic streaming functionality with AzureAIClient."""
async with (
temporary_chat_client(agent_name="BasicRunStreamingAgent") as chat_client,
ChatAgent(chat_client=chat_client) as agent,
):
full_message: str = ""
async for chunk in agent.run_stream("Please respond with exactly: 'This is a streaming response test.'"):
assert chunk is not None
assert isinstance(chunk, AgentRunResponseUpdate)
if chunk.text:
full_message += chunk.text
# Validate streaming response
assert len(full_message) > 0
assert "streaming response test" in full_message.lower()
@pytest.mark.flaky
@skip_if_azure_ai_integration_tests_disabled
async def test_azure_ai_chat_client_agent_with_tools() -> None:
"""Test ChatAgent tools with AzureAIClient."""
async with (
temporary_chat_client(agent_name="RunToolsAgent") as chat_client,
ChatAgent(chat_client=chat_client, tools=[get_weather]) as agent,
):
response = await agent.run("What's the weather like in Seattle?")
# Validate response
assert isinstance(response, AgentRunResponse)
assert response.text is not None
assert len(response.text) > 0
assert any(word in response.text.lower() for word in ["sunny", "25"])