From cec8bd348ed106b3501dc5cea29ea38257db948c Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Mon, 26 Jan 2026 13:11:15 +0000
Subject: [PATCH] .NET: Improve unit test coverage for
Microsoft.Agents.AI.Anthropic (#3382)
* Initial plan
* Add unit tests to improve coverage for Microsoft.Agents.AI.Anthropic
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
* Update instruction verification tests to check agent.Instructions property
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
* Update unit tests with proper assertions for agent scenarios
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
* Add assertions for tools and maxTokens in Anthropic extension tests
* Add proper assertions for tools and maxTokens in Anthropic tests
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
---
.../AnthropicBetaServiceExtensionsTests.cs | 199 ++++++++++++++++++
.../AnthropicClientExtensionsTests.cs | 199 ++++++++++++++++++
2 files changed, 398 insertions(+)
diff --git a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs
index 91d2cb988a..8415b09b25 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs
@@ -188,6 +188,205 @@ public sealed class AnthropicBetaServiceExtensionsTests
Assert.Equal("options", exception.ParamName);
}
+ ///
+ /// Verify that CreateAIAgent with tools correctly assigns tools to ChatOptions.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithTools_AssignsToolsCorrectly()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+ IList tools = [AIFunctionFactory.Create(() => "test result", "TestFunction", "A test function")];
+
+ // Act
+ var agent = chatClient.Beta.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ tools: tools);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ // When tools are provided, ChatOptions is created but instructions remain null
+ Assert.Null(agent.Instructions);
+
+ // Verify that tools are registered in the FunctionInvokingChatClient
+ var functionInvokingClient = agent.GetService();
+ Assert.NotNull(functionInvokingClient);
+ Assert.NotNull(functionInvokingClient.AdditionalTools);
+ Assert.Contains(functionInvokingClient.AdditionalTools, t => t is AIFunction func && func.Name == "TestFunction");
+ }
+
+ ///
+ /// Verify that CreateAIAgent with explicit defaultMaxTokens uses the provided value.
+ ///
+ [Fact]
+ public async Task CreateAIAgent_WithExplicitMaxTokens_UsesProvidedValueAsync()
+ {
+ // Arrange
+ int capturedMaxTokens = 0;
+ var handler = new CapturingHttpHandler(request =>
+ {
+ // Parse the request body to capture max_tokens
+ var content = request.Content?.ReadAsStringAsync().GetAwaiter().GetResult();
+ if (content is not null)
+ {
+ var json = System.Text.Json.JsonDocument.Parse(content);
+ if (json.RootElement.TryGetProperty("max_tokens", out var maxTokens))
+ {
+ capturedMaxTokens = maxTokens.GetInt32();
+ }
+ }
+ });
+
+ var client = new AnthropicClient
+ {
+ HttpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") },
+ APIKey = "test-key"
+ };
+
+ // Act
+ var agent = client.Beta.AsAIAgent(
+ model: "claude-haiku-4-5",
+ name: "Test Agent",
+ defaultMaxTokens: 8192);
+
+ // Invoke the agent to trigger the request
+ var thread = await agent.GetNewThreadAsync();
+ try
+ {
+ await agent.RunAsync("Test message", thread);
+ }
+ catch
+ {
+ // Expected to fail since we're using a test handler
+ }
+
+ // Assert
+ Assert.Equal(8192, capturedMaxTokens);
+ }
+
+ ///
+ /// HTTP handler that captures requests for verification.
+ ///
+ private sealed class CapturingHttpHandler : HttpMessageHandler
+ {
+ private readonly Action _captureRequest;
+
+ public CapturingHttpHandler(Action captureRequest)
+ {
+ this._captureRequest = captureRequest;
+ }
+
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ this._captureRequest(request);
+ return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
+ {
+ Content = new StringContent("{\"error\": \"test\"}")
+ });
+ }
+ }
+
+ ///
+ /// Verify that CreateAIAgent with tools and instructions correctly assigns both.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithToolsAndInstructions_AssignsBothCorrectly()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+ IList tools = [AIFunctionFactory.Create(() => "test result", "TestFunction", "A test function")];
+
+ // Act
+ var agent = chatClient.Beta.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ instructions: "Test instructions",
+ tools: tools);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Equal("Test instructions", agent.Instructions);
+
+ // Verify that tools are registered in the FunctionInvokingChatClient
+ var functionInvokingClient = agent.GetService();
+ Assert.NotNull(functionInvokingClient);
+ Assert.NotNull(functionInvokingClient.AdditionalTools);
+ Assert.Contains(functionInvokingClient.AdditionalTools, t => t is AIFunction func && func.Name == "TestFunction");
+ }
+
+ ///
+ /// Verify that CreateAIAgent with empty tools list does not assign tools.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithEmptyTools_DoesNotAssignTools()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+ IList tools = [];
+
+ // Act
+ var agent = chatClient.Beta.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ tools: tools);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ // With empty tools and no instructions, agent instructions remain null
+ Assert.Null(agent.Instructions);
+
+ // Verify that FunctionInvokingChatClient has no additional tools assigned
+ var functionInvokingClient = agent.GetService();
+ Assert.NotNull(functionInvokingClient);
+ Assert.True(functionInvokingClient.AdditionalTools is null or { Count: 0 });
+ }
+
+ ///
+ /// Verify that CreateAIAgent with null instructions does not set instructions.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithNullInstructions_DoesNotSetInstructions()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+
+ // Act
+ var agent = chatClient.Beta.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ instructions: null);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Null(agent.Instructions);
+ }
+
+ ///
+ /// Verify that CreateAIAgent with whitespace instructions does not set instructions.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithWhitespaceInstructions_DoesNotSetInstructions()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+
+ // Act
+ var agent = chatClient.Beta.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ instructions: " ");
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Null(agent.Instructions);
+ }
+
///
/// Test custom chat client that can be used to verify clientFactory functionality.
///
diff --git a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs
index 90f20d15c3..cd7112fc5b 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs
@@ -254,4 +254,203 @@ public sealed class AnthropicClientExtensionsTests
Assert.Equal("options", exception.ParamName);
}
+
+ ///
+ /// Verify that CreateAIAgent with tools correctly assigns tools to ChatOptions.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithTools_AssignsToolsCorrectly()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+ IList tools = [AIFunctionFactory.Create(() => "test result", "TestFunction", "A test function")];
+
+ // Act
+ var agent = chatClient.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ tools: tools);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ // When tools are provided, ChatOptions is created but instructions remain null
+ Assert.Null(agent.Instructions);
+
+ // Verify that tools are registered in the FunctionInvokingChatClient
+ var functionInvokingClient = agent.GetService();
+ Assert.NotNull(functionInvokingClient);
+ Assert.NotNull(functionInvokingClient.AdditionalTools);
+ Assert.Contains(functionInvokingClient.AdditionalTools, t => t is AIFunction func && func.Name == "TestFunction");
+ }
+
+ ///
+ /// Verify that CreateAIAgent with explicit defaultMaxTokens uses the provided value.
+ ///
+ [Fact]
+ public async Task CreateAIAgent_WithExplicitMaxTokens_UsesProvidedValueAsync()
+ {
+ // Arrange
+ int capturedMaxTokens = 0;
+ var handler = new CapturingHttpHandler(request =>
+ {
+ // Parse the request body to capture max_tokens
+ var content = request.Content?.ReadAsStringAsync().GetAwaiter().GetResult();
+ if (content is not null)
+ {
+ var json = System.Text.Json.JsonDocument.Parse(content);
+ if (json.RootElement.TryGetProperty("max_tokens", out var maxTokens))
+ {
+ capturedMaxTokens = maxTokens.GetInt32();
+ }
+ }
+ });
+
+ var client = new AnthropicClient
+ {
+ HttpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") },
+ APIKey = "test-key"
+ };
+
+ // Act
+ var agent = client.AsAIAgent(
+ model: "claude-haiku-4-5",
+ name: "Test Agent",
+ defaultMaxTokens: 8192);
+
+ // Invoke the agent to trigger the request
+ var thread = await agent.GetNewThreadAsync();
+ try
+ {
+ await agent.RunAsync("Test message", thread);
+ }
+ catch
+ {
+ // Expected to fail since we're using a test handler
+ }
+
+ // Assert
+ Assert.Equal(8192, capturedMaxTokens);
+ }
+
+ ///
+ /// HTTP handler that captures requests for verification.
+ ///
+ private sealed class CapturingHttpHandler : HttpMessageHandler
+ {
+ private readonly Action _captureRequest;
+
+ public CapturingHttpHandler(Action captureRequest)
+ {
+ this._captureRequest = captureRequest;
+ }
+
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ this._captureRequest(request);
+ return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
+ {
+ Content = new StringContent("{\"error\": \"test\"}")
+ });
+ }
+ }
+
+ ///
+ /// Verify that CreateAIAgent with tools and instructions correctly assigns both.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithToolsAndInstructions_AssignsBothCorrectly()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+ IList tools = [AIFunctionFactory.Create(() => "test result", "TestFunction", "A test function")];
+
+ // Act
+ var agent = chatClient.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ instructions: "Test instructions",
+ tools: tools);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Equal("Test instructions", agent.Instructions);
+
+ // Verify that tools are registered in the FunctionInvokingChatClient
+ var functionInvokingClient = agent.GetService();
+ Assert.NotNull(functionInvokingClient);
+ Assert.NotNull(functionInvokingClient.AdditionalTools);
+ Assert.Contains(functionInvokingClient.AdditionalTools, t => t is AIFunction func && func.Name == "TestFunction");
+ }
+
+ ///
+ /// Verify that CreateAIAgent with empty tools list does not assign tools.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithEmptyTools_DoesNotAssignTools()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+ IList tools = [];
+
+ // Act
+ var agent = chatClient.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ tools: tools);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ // With empty tools and no instructions, agent instructions remain null
+ Assert.Null(agent.Instructions);
+
+ // Verify that FunctionInvokingChatClient has no additional tools assigned
+ var functionInvokingClient = agent.GetService();
+ Assert.NotNull(functionInvokingClient);
+ Assert.True(functionInvokingClient.AdditionalTools is null or { Count: 0 });
+ }
+
+ ///
+ /// Verify that CreateAIAgent with null instructions does not set instructions.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithNullInstructions_DoesNotSetInstructions()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+
+ // Act
+ var agent = chatClient.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ instructions: null);
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Null(agent.Instructions);
+ }
+
+ ///
+ /// Verify that CreateAIAgent with whitespace instructions does not set instructions.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithWhitespaceInstructions_DoesNotSetInstructions()
+ {
+ // Arrange
+ var chatClient = new TestAnthropicChatClient();
+
+ // Act
+ var agent = chatClient.AsAIAgent(
+ model: "test-model",
+ name: "Test Agent",
+ instructions: " ");
+
+ // Assert
+ Assert.NotNull(agent);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Null(agent.Instructions);
+ }
}