diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index 9b95114b167..a33213fdfee 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -144,7 +144,6 @@
-
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/BasicStreamingTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/BasicStreamingTests.cs
index 97addd3d885..76a23fb60cb 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/BasicStreamingTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/BasicStreamingTests.cs
@@ -12,7 +12,6 @@
using System.Threading.Tasks;
using AGUI.Abstractions;
using AGUI.Client;
-using FluentAssertions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.TestHost;
@@ -45,16 +44,16 @@ public async Task ClientReceivesStreamedAssistantMessageAsync()
}
// Assert
- session.Should().NotBeNull();
+ Assert.NotNull(session);
- updates.Should().NotBeEmpty();
- updates.Should().AllSatisfy(u => u.Role.Should().Be(ChatRole.Assistant));
+ Assert.NotEmpty(updates);
+ Assert.All(updates, u => Assert.Equal(ChatRole.Assistant, u.Role));
// Verify assistant response message
AgentResponse response = updates.ToAgentResponse();
- response.Messages.Should().HaveCount(1);
- response.Messages[0].Role.Should().Be(ChatRole.Assistant);
- response.Messages[0].Text.Should().Be("Hello from fake agent!");
+ ChatMessage responseMessage = Assert.Single(response.Messages);
+ Assert.Equal(ChatRole.Assistant, responseMessage.Role);
+ Assert.Equal("Hello from fake agent!", responseMessage.Text);
}
[Fact]
@@ -76,39 +75,39 @@ public async Task ClientReceivesRunLifecycleEventsAsync()
}
// Assert - RunStarted should be the first update
- updates.Should().NotBeEmpty();
- updates[0].ResponseId.Should().NotBeNullOrEmpty();
+ Assert.NotEmpty(updates);
+ Assert.False(string.IsNullOrEmpty(updates[0].ResponseId));
ChatResponseUpdate firstUpdate = updates[0].AsChatResponseUpdate();
// The AG-UI thread id is surfaced on the RUN_STARTED event (the new AGUI.Client keeps the
// client stateless and never populates ChatResponseUpdate.ConversationId).
string? threadId = (firstUpdate.RawRepresentation as RunStartedEvent)?.ThreadId;
string? runId = updates[0].ResponseId;
- threadId.Should().NotBeNullOrEmpty();
- runId.Should().NotBeNullOrEmpty();
+ Assert.False(string.IsNullOrEmpty(threadId));
+ Assert.False(string.IsNullOrEmpty(runId));
// Should have received text updates
- updates.Should().Contain(u => !string.IsNullOrEmpty(u.Text));
+ Assert.Contains(updates, u => !string.IsNullOrEmpty(u.Text));
// All text content updates should have the same message ID
List textUpdates = updates.Where(u => !string.IsNullOrEmpty(u.Text)).ToList();
- textUpdates.Should().NotBeEmpty();
+ Assert.NotEmpty(textUpdates);
string? firstMessageId = textUpdates.FirstOrDefault()?.MessageId;
- firstMessageId.Should().NotBeNullOrEmpty();
- textUpdates.Should().AllSatisfy(u => u.MessageId.Should().Be(firstMessageId));
+ Assert.False(string.IsNullOrEmpty(firstMessageId));
+ Assert.All(textUpdates, u => Assert.Equal(firstMessageId, u.MessageId));
// RunFinished should be the last update
AgentResponseUpdate lastUpdate = updates[^1];
- lastUpdate.ResponseId.Should().Be(runId);
+ Assert.Equal(runId, lastUpdate.ResponseId);
ChatResponseUpdate lastChatUpdate = lastUpdate.AsChatResponseUpdate();
// The stateless client never populates ChatResponseUpdate.ConversationId; thread identity stays
// on the AG-UI wire events instead, so verify the RUN_FINISHED event carries the same ids.
- lastChatUpdate.ConversationId.Should().BeNull();
+ Assert.Null(lastChatUpdate.ConversationId);
RunFinishedEvent? runFinished = updates
.Select(u => u.AsChatResponseUpdate().RawRepresentation as RunFinishedEvent)
.FirstOrDefault(e => e is not null);
- runFinished.Should().NotBeNull();
- runFinished!.ThreadId.Should().Be(threadId);
- runFinished.RunId.Should().Be(runId);
+ Assert.NotNull(runFinished);
+ Assert.Equal(threadId, runFinished!.ThreadId);
+ Assert.Equal(runId, runFinished.RunId);
}
[Fact]
@@ -125,9 +124,9 @@ public async Task RunAsyncAggregatesStreamingUpdatesAsync()
AgentResponse response = await agent.RunAsync([userMessage], session, new AgentRunOptions(), CancellationToken.None);
// Assert
- response.Messages.Should().NotBeEmpty();
- response.Messages.Should().Contain(m => m.Role == ChatRole.Assistant);
- response.Messages.Should().Contain(m => m.Text == "Hello from fake agent!");
+ Assert.NotEmpty(response.Messages);
+ Assert.Contains(response.Messages, m => m.Role == ChatRole.Assistant);
+ Assert.Contains(response.Messages, m => m.Text == "Hello from fake agent!");
}
[Fact]
@@ -148,9 +147,9 @@ public async Task AGUIChatClientBackedAgentUsesLocalChatHistoryAcrossTurnsAsync(
}
// Assert first turn completed
- firstTurnUpdates.Should().Contain(u => !string.IsNullOrEmpty(u.Text));
- firstTurnUpdates.Should().AllSatisfy(u => u.AsChatResponseUpdate().ConversationId.Should().BeNull());
- chatClientSession.ConversationId.Should().BeNull();
+ Assert.Contains(firstTurnUpdates, u => !string.IsNullOrEmpty(u.Text));
+ Assert.All(firstTurnUpdates, u => Assert.Null(u.AsChatResponseUpdate().ConversationId));
+ Assert.Null(chatClientSession.ConversationId);
// Act - Second turn with another message
ChatMessage secondUserMessage = new(ChatRole.User, "Second question");
@@ -161,34 +160,34 @@ public async Task AGUIChatClientBackedAgentUsesLocalChatHistoryAcrossTurnsAsync(
}
// Assert second turn completed
- secondTurnUpdates.Should().Contain(u => !string.IsNullOrEmpty(u.Text));
- secondTurnUpdates.Should().AllSatisfy(u => u.AsChatResponseUpdate().ConversationId.Should().BeNull());
- chatClientSession.ConversationId.Should().BeNull();
+ Assert.Contains(secondTurnUpdates, u => !string.IsNullOrEmpty(u.Text));
+ Assert.All(secondTurnUpdates, u => Assert.Null(u.AsChatResponseUpdate().ConversationId));
+ Assert.Null(chatClientSession.ConversationId);
// Verify the local provider retained both turns.
- InMemoryChatHistoryProvider historyProvider = agent.ChatHistoryProvider.Should().BeOfType().Subject;
+ InMemoryChatHistoryProvider historyProvider = Assert.IsType(agent.ChatHistoryProvider);
List history = historyProvider.GetMessages(chatClientSession);
- history.Should().HaveCount(4);
- history[0].Role.Should().Be(ChatRole.User);
- history[0].Text.Should().Be("First question");
- history[1].Role.Should().Be(ChatRole.Assistant);
- history[1].Text.Should().Be("Hello from fake agent!");
- history[2].Role.Should().Be(ChatRole.User);
- history[2].Text.Should().Be("Second question");
- history[3].Role.Should().Be(ChatRole.Assistant);
- history[3].Text.Should().Be("Hello from fake agent!");
+ Assert.Equal(4, history.Count);
+ Assert.Equal(ChatRole.User, history[0].Role);
+ Assert.Equal("First question", history[0].Text);
+ Assert.Equal(ChatRole.Assistant, history[1].Role);
+ Assert.Equal("Hello from fake agent!", history[1].Text);
+ Assert.Equal(ChatRole.User, history[2].Role);
+ Assert.Equal("Second question", history[2].Text);
+ Assert.Equal(ChatRole.Assistant, history[3].Role);
+ Assert.Equal("Hello from fake agent!", history[3].Text);
// Verify first turn assistant response.
AgentResponse firstResponse = firstTurnUpdates.ToAgentResponse();
- firstResponse.Messages.Should().HaveCount(1);
- firstResponse.Messages[0].Role.Should().Be(ChatRole.Assistant);
- firstResponse.Messages[0].Text.Should().Be("Hello from fake agent!");
+ ChatMessage firstResponseMessage = Assert.Single(firstResponse.Messages);
+ Assert.Equal(ChatRole.Assistant, firstResponseMessage.Role);
+ Assert.Equal("Hello from fake agent!", firstResponseMessage.Text);
// Verify second turn assistant response.
AgentResponse secondResponse = secondTurnUpdates.ToAgentResponse();
- secondResponse.Messages.Should().HaveCount(1);
- secondResponse.Messages[0].Role.Should().Be(ChatRole.Assistant);
- secondResponse.Messages[0].Text.Should().Be("Hello from fake agent!");
+ ChatMessage secondResponseMessage = Assert.Single(secondResponse.Messages);
+ Assert.Equal(ChatRole.Assistant, secondResponseMessage.Role);
+ Assert.Equal("Hello from fake agent!", secondResponseMessage.Text);
}
[Fact]
@@ -211,16 +210,16 @@ public async Task AgentSendsMultipleMessagesInOneTurnAsync()
// Assert - Should have received text updates with different message IDs
List textUpdates = updates.Where(u => !string.IsNullOrEmpty(u.Text)).ToList();
- textUpdates.Should().NotBeEmpty();
+ Assert.NotEmpty(textUpdates);
// Extract unique message IDs
List messageIds = textUpdates.Select(u => u.MessageId).Where(id => !string.IsNullOrEmpty(id)).Distinct().ToList()!;
- messageIds.Should().HaveCountGreaterThan(1, "agent should send multiple messages");
+ Assert.True(messageIds.Count > 1);
// Verify assistant messages from updates
AgentResponse response = updates.ToAgentResponse();
- response.Messages.Should().HaveCountGreaterThan(1);
- response.Messages.Should().AllSatisfy(m => m.Role.Should().Be(ChatRole.Assistant));
+ Assert.True(response.Messages.Count > 1);
+ Assert.All(response.Messages, m => Assert.Equal(ChatRole.Assistant, m.Role));
}
[Fact]
@@ -249,14 +248,14 @@ public async Task UserSendsMultipleMessagesAtOnceAsync()
}
// Assert - Should have received assistant response
- updates.Should().Contain(u => !string.IsNullOrEmpty(u.Text));
- updates.Should().Contain(u => u.Role == ChatRole.Assistant);
+ Assert.Contains(updates, u => !string.IsNullOrEmpty(u.Text));
+ Assert.Contains(updates, u => u.Role == ChatRole.Assistant);
// Verify assistant response message
AgentResponse response = updates.ToAgentResponse();
- response.Messages.Should().HaveCount(1);
- response.Messages[0].Role.Should().Be(ChatRole.Assistant);
- response.Messages[0].Text.Should().Be("Hello from fake agent!");
+ ChatMessage responseMessage = Assert.Single(response.Messages);
+ Assert.Equal(ChatRole.Assistant, responseMessage.Role);
+ Assert.Equal("Hello from fake agent!", responseMessage.Text);
}
[Fact]
@@ -276,8 +275,8 @@ public async Task PostMalformedOrEmptyBody_ReturnsBadRequestAsync()
using HttpResponseMessage emptyResponse = await this._client!.PostAsync(endpoint, empty);
// Assert - the hosting glue rejects both with 400 rather than 5xx.
- malformedResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- emptyResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
+ Assert.Equal(System.Net.HttpStatusCode.BadRequest, malformedResponse.StatusCode);
+ Assert.Equal(System.Net.HttpStatusCode.BadRequest, emptyResponse.StatusCode);
}
private async Task SetupTestServerAsync(bool useMultiMessageAgent = false)
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ForwardedPropertiesTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ForwardedPropertiesTests.cs
index c3582459d53..dcf9cdbf4ba 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ForwardedPropertiesTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ForwardedPropertiesTests.cs
@@ -15,7 +15,6 @@
using AGUI.Abstractions;
using AGUI.Client;
using AGUI.Server;
-using FluentAssertions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.TestHost;
@@ -54,10 +53,10 @@ [new ChatMessage(ChatRole.User, "test client forwarding")],
}
// Assert
- fakeAgent.ReceivedContext.Should().ContainSingle();
- fakeAgent.ReceivedContext![0].Description.Should().Be("Current user");
- fakeAgent.ReceivedContext[0].Value.Should().Be("Ada Lovelace");
- fakeAgent.ReceivedForwardedProperties.GetProperty("tenantId").GetString().Should().Be("tenant-123");
+ Assert.Single(fakeAgent.ReceivedContext ?? []);
+ Assert.Equal("Current user", fakeAgent.ReceivedContext![0].Description);
+ Assert.Equal("Ada Lovelace", fakeAgent.ReceivedContext[0].Value);
+ Assert.Equal("tenant-123", fakeAgent.ReceivedForwardedProperties.GetProperty("tenantId").GetString());
}
[Fact]
@@ -83,10 +82,10 @@ public async Task ForwardedProps_AreParsedAndPassedToAgent_WhenProvidedInRequest
HttpResponseMessage response = await this._client!.PostAsync(new Uri("/agent", UriKind.Relative), content);
// Assert
- response.IsSuccessStatusCode.Should().BeTrue();
- fakeAgent.ReceivedForwardedProperties.ValueKind.Should().Be(JsonValueKind.Object);
- fakeAgent.ReceivedForwardedProperties.GetProperty("customProp").GetString().Should().Be("customValue");
- fakeAgent.ReceivedForwardedProperties.GetProperty("sessionId").GetString().Should().Be("test-session-123");
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(JsonValueKind.Object, fakeAgent.ReceivedForwardedProperties.ValueKind);
+ Assert.Equal("customValue", fakeAgent.ReceivedForwardedProperties.GetProperty("customProp").GetString());
+ Assert.Equal("test-session-123", fakeAgent.ReceivedForwardedProperties.GetProperty("sessionId").GetString());
}
[Fact]
@@ -114,16 +113,16 @@ public async Task ForwardedProps_WithNestedObjects_AreCorrectlyParsedAsync()
HttpResponseMessage response = await this._client!.PostAsync(new Uri("/agent", UriKind.Relative), content);
// Assert
- response.IsSuccessStatusCode.Should().BeTrue();
- fakeAgent.ReceivedForwardedProperties.ValueKind.Should().Be(JsonValueKind.Object);
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(JsonValueKind.Object, fakeAgent.ReceivedForwardedProperties.ValueKind);
JsonElement user = fakeAgent.ReceivedForwardedProperties.GetProperty("user");
- user.GetProperty("id").GetString().Should().Be("user-1");
- user.GetProperty("name").GetString().Should().Be("Test User");
+ Assert.Equal("user-1", user.GetProperty("id").GetString());
+ Assert.Equal("Test User", user.GetProperty("name").GetString());
JsonElement metadata = fakeAgent.ReceivedForwardedProperties.GetProperty("metadata");
- metadata.GetProperty("version").GetString().Should().Be("1.0");
- metadata.GetProperty("feature").GetString().Should().Be("test");
+ Assert.Equal("1.0", metadata.GetProperty("version").GetString());
+ Assert.Equal("test", metadata.GetProperty("feature").GetString());
}
[Fact]
@@ -151,16 +150,16 @@ public async Task ForwardedProps_WithArrays_AreCorrectlyParsedAsync()
HttpResponseMessage response = await this._client!.PostAsync(new Uri("/agent", UriKind.Relative), content);
// Assert
- response.IsSuccessStatusCode.Should().BeTrue();
- fakeAgent.ReceivedForwardedProperties.ValueKind.Should().Be(JsonValueKind.Object);
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(JsonValueKind.Object, fakeAgent.ReceivedForwardedProperties.ValueKind);
JsonElement tags = fakeAgent.ReceivedForwardedProperties.GetProperty("tags");
- tags.GetArrayLength().Should().Be(3);
- tags[0].GetString().Should().Be("tag1");
+ Assert.Equal(3, tags.GetArrayLength());
+ Assert.Equal("tag1", tags[0].GetString());
JsonElement scores = fakeAgent.ReceivedForwardedProperties.GetProperty("scores");
- scores.GetArrayLength().Should().Be(5);
- scores[2].GetInt32().Should().Be(3);
+ Assert.Equal(5, scores.GetArrayLength());
+ Assert.Equal(3, scores[2].GetInt32());
}
[Fact]
@@ -185,7 +184,7 @@ public async Task ForwardedProps_WhenEmpty_DoesNotCauseErrorsAsync()
HttpResponseMessage response = await this._client!.PostAsync(new Uri("/agent", UriKind.Relative), content);
// Assert
- response.IsSuccessStatusCode.Should().BeTrue();
+ Assert.True(response.IsSuccessStatusCode);
}
[Fact]
@@ -209,8 +208,8 @@ public async Task ForwardedProps_WhenNotProvided_AgentStillWorksAsync()
HttpResponseMessage response = await this._client!.PostAsync(new Uri("/agent", UriKind.Relative), content);
// Assert
- response.IsSuccessStatusCode.Should().BeTrue();
- fakeAgent.ReceivedForwardedProperties.ValueKind.Should().Be(JsonValueKind.Undefined);
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(JsonValueKind.Undefined, fakeAgent.ReceivedForwardedProperties.ValueKind);
}
[Fact]
@@ -243,20 +242,20 @@ public async Task ForwardedProps_ReturnsValidSSEResponse_WithTextDeltaEventsAsyn
}
// Assert
- events.Should().NotBeEmpty();
+ Assert.NotEmpty(events);
// SSE events have EventType = "message" and the actual type is in the JSON data
// Should have run_started event
- events.Should().Contain(e => e.Data != null && e.Data.Contains("\"type\":\"RUN_STARTED\""));
+ Assert.Contains(events, e => e.Data?.Contains("\"type\":\"RUN_STARTED\"") == true);
// Should have text_message_start event
- events.Should().Contain(e => e.Data != null && e.Data.Contains("\"type\":\"TEXT_MESSAGE_START\""));
+ Assert.Contains(events, e => e.Data?.Contains("\"type\":\"TEXT_MESSAGE_START\"") == true);
// Should have text_message_content event with the response text
- events.Should().Contain(e => e.Data != null && e.Data.Contains("\"type\":\"TEXT_MESSAGE_CONTENT\""));
+ Assert.Contains(events, e => e.Data?.Contains("\"type\":\"TEXT_MESSAGE_CONTENT\"") == true);
// Should have run_finished event
- events.Should().Contain(e => e.Data != null && e.Data.Contains("\"type\":\"RUN_FINISHED\""));
+ Assert.Contains(events, e => e.Data?.Contains("\"type\":\"RUN_FINISHED\"") == true);
}
[Fact]
@@ -288,15 +287,15 @@ public async Task ForwardedProps_WithMixedTypes_AreCorrectlyParsedAsync()
HttpResponseMessage response = await this._client!.PostAsync(new Uri("/agent", UriKind.Relative), content);
// Assert
- response.IsSuccessStatusCode.Should().BeTrue();
- fakeAgent.ReceivedForwardedProperties.ValueKind.Should().Be(JsonValueKind.Object);
-
- fakeAgent.ReceivedForwardedProperties.GetProperty("stringProp").GetString().Should().Be("text");
- fakeAgent.ReceivedForwardedProperties.GetProperty("numberProp").GetInt32().Should().Be(42);
- fakeAgent.ReceivedForwardedProperties.GetProperty("boolProp").GetBoolean().Should().BeTrue();
- fakeAgent.ReceivedForwardedProperties.GetProperty("nullProp").ValueKind.Should().Be(JsonValueKind.Null);
- fakeAgent.ReceivedForwardedProperties.GetProperty("arrayProp").GetArrayLength().Should().Be(3);
- fakeAgent.ReceivedForwardedProperties.GetProperty("objectProp").GetProperty("nested").GetString().Should().Be("value");
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(JsonValueKind.Object, fakeAgent.ReceivedForwardedProperties.ValueKind);
+
+ Assert.Equal("text", fakeAgent.ReceivedForwardedProperties.GetProperty("stringProp").GetString());
+ Assert.Equal(42, fakeAgent.ReceivedForwardedProperties.GetProperty("numberProp").GetInt32());
+ Assert.True(fakeAgent.ReceivedForwardedProperties.GetProperty("boolProp").GetBoolean());
+ Assert.Equal(JsonValueKind.Null, fakeAgent.ReceivedForwardedProperties.GetProperty("nullProp").ValueKind);
+ Assert.Equal(3, fakeAgent.ReceivedForwardedProperties.GetProperty("arrayProp").GetArrayLength());
+ Assert.Equal("value", fakeAgent.ReceivedForwardedProperties.GetProperty("objectProp").GetProperty("nested").GetString());
}
private async Task SetupTestServerAsync(FakeForwardedPropsAgent fakeAgent)
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests.csproj
index 019f0eb7a16..a65db7c2cf5 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests.csproj
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests.csproj
@@ -11,7 +11,6 @@
-
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SessionPersistenceTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SessionPersistenceTests.cs
index 3c9c3a0281a..576f6c2d1c3 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SessionPersistenceTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SessionPersistenceTests.cs
@@ -12,7 +12,6 @@
using System.Threading.Tasks;
using AGUI.Abstractions;
using AGUI.Client;
-using FluentAssertions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.TestHost;
@@ -53,11 +52,11 @@ public async Task MultiTurnWithSessionStore_PersistsSessionAcrossRequestsAsync()
RunStartedEvent? firstRunStarted = firstTurnUpdates
.Select(u => u.AsChatResponseUpdate().RawRepresentation as RunStartedEvent)
.FirstOrDefault(e => e is not null);
- firstRunStarted.Should().NotBeNull();
+ Assert.NotNull(firstRunStarted);
string threadId = firstRunStarted!.ThreadId;
string previousRunId = firstRunStarted.RunId;
- threadId.Should().NotBeNullOrEmpty();
- previousRunId.Should().NotBeNullOrEmpty();
+ Assert.False(string.IsNullOrEmpty(threadId));
+ Assert.False(string.IsNullOrEmpty(previousRunId));
ChatMessage secondUserMessage = new(ChatRole.User, "Second message");
var continuationOptions = new ChatClientAgentRunOptions
@@ -82,14 +81,14 @@ public async Task MultiTurnWithSessionStore_PersistsSessionAcrossRequestsAsync()
// If session persistence were broken, both turns would return "Turn 1"
// because a fresh session (with turn count 0) would be created each time.
AgentResponse firstResponse = firstTurnUpdates.ToAgentResponse();
- firstResponse.Messages.Should().HaveCount(1);
- firstResponse.Messages[0].Role.Should().Be(ChatRole.Assistant);
- firstResponse.Messages[0].Text.Should().Contain("Turn 1:");
+ ChatMessage firstResponseMessage = Assert.Single(firstResponse.Messages);
+ Assert.Equal(ChatRole.Assistant, firstResponseMessage.Role);
+ Assert.Contains("Turn 1:", firstResponseMessage.Text);
AgentResponse secondResponse = secondTurnUpdates.ToAgentResponse();
- secondResponse.Messages.Should().HaveCount(1);
- secondResponse.Messages[0].Role.Should().Be(ChatRole.Assistant);
- secondResponse.Messages[0].Text.Should().Contain("Turn 2:");
+ ChatMessage secondResponseMessage = Assert.Single(secondResponse.Messages);
+ Assert.Equal(ChatRole.Assistant, secondResponseMessage.Role);
+ Assert.Contains("Turn 2:", secondResponseMessage.Text);
}
[Fact]
@@ -111,13 +110,13 @@ public async Task MapAGUIServer_WithAgentName_StreamsResponseCorrectlyAsync()
}
// Assert
- updates.Should().NotBeEmpty();
- updates.Should().AllSatisfy(u => u.Role.Should().Be(ChatRole.Assistant));
+ Assert.NotEmpty(updates);
+ Assert.All(updates, u => Assert.Equal(ChatRole.Assistant, u.Role));
AgentResponse response = updates.ToAgentResponse();
- response.Messages.Should().HaveCount(1);
- response.Messages[0].Role.Should().Be(ChatRole.Assistant);
- response.Messages[0].Text.Should().Be("Turn 1: Hello from session agent!");
+ ChatMessage responseMessage = Assert.Single(response.Messages);
+ Assert.Equal(ChatRole.Assistant, responseMessage.Role);
+ Assert.Equal("Turn 1: Hello from session agent!", responseMessage.Text);
}
private async Task SetupTestServerWithSessionStoreAsync()
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SharedStateTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SharedStateTests.cs
index 802dbaa651b..079ab79d1d1 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SharedStateTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SharedStateTests.cs
@@ -13,7 +13,6 @@
using AGUI.Abstractions;
using AGUI.Client;
using AGUI.Server;
-using FluentAssertions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.TestHost;
@@ -51,12 +50,12 @@ public async Task StateSnapshot_IsSurfacedAsRawStateSnapshotEventAsync()
}
// Assert - the state snapshot is surfaced as a StateSnapshotEvent raw representation.
- updates.Should().NotBeEmpty();
+ Assert.NotEmpty(updates);
StateSnapshotEvent? snapshot = FindStateSnapshot(updates);
- snapshot.Should().NotBeNull("should receive a STATE_SNAPSHOT event");
- snapshot!.Snapshot.GetProperty("counter").GetInt32().Should().Be(43, "state should be incremented");
- snapshot.Snapshot.GetProperty("status").GetString().Should().Be("active");
+ Assert.NotNull(snapshot);
+ Assert.Equal(43, snapshot!.Snapshot.GetProperty("counter").GetInt32());
+ Assert.Equal("active", snapshot.Snapshot.GetProperty("status").GetString());
}
[Fact]
@@ -83,12 +82,12 @@ public async Task StateSnapshot_UpdateHasAssistantRoleAndNoConversationIdAsync()
// ConversationId unset (state identity stays on the AG-UI wire events).
AgentResponseUpdate? stateUpdate = updates
.FirstOrDefault(u => u.AsChatResponseUpdate().RawRepresentation is StateSnapshotEvent);
- stateUpdate.Should().NotBeNull();
+ Assert.NotNull(stateUpdate);
ChatResponseUpdate chatUpdate = stateUpdate!.AsChatResponseUpdate();
- chatUpdate.RawRepresentation.Should().BeOfType();
- chatUpdate.ConversationId.Should().BeNull();
- chatUpdate.Role.Should().Be(ChatRole.Assistant);
+ Assert.True(chatUpdate.RawRepresentation is StateSnapshotEvent);
+ Assert.Null(chatUpdate.ConversationId);
+ Assert.Equal(ChatRole.Assistant, chatUpdate.Role);
}
[Fact]
@@ -114,13 +113,13 @@ public async Task ComplexState_WithNestedObjectsAndArrays_RoundTripsCorrectlyAsy
// Assert
StateSnapshotEvent? snapshot = FindStateSnapshot(updates);
- snapshot.Should().NotBeNull();
+ Assert.NotNull(snapshot);
JsonElement receivedState = snapshot!.Snapshot;
- receivedState.GetProperty("sessionId").GetString().Should().Be("test-123");
- receivedState.GetProperty("nested").GetProperty("count").GetInt32().Should().Be(10);
- receivedState.GetProperty("array").GetArrayLength().Should().Be(3);
- receivedState.GetProperty("tags").GetArrayLength().Should().Be(2);
+ Assert.Equal("test-123", receivedState.GetProperty("sessionId").GetString());
+ Assert.Equal(10, receivedState.GetProperty("nested").GetProperty("count").GetInt32());
+ Assert.Equal(3, receivedState.GetProperty("array").GetArrayLength());
+ Assert.Equal(2, receivedState.GetProperty("tags").GetArrayLength());
}
[Fact]
@@ -145,8 +144,8 @@ public async Task StateSnapshot_CanBeUsedInSubsequentRequest_ForStateRoundTripAs
// Feed the returned state snapshot back into the second round.
StateSnapshotEvent? firstSnapshot = FindStateSnapshot(firstRoundUpdates);
- firstSnapshot.Should().NotBeNull();
- firstSnapshot!.Snapshot.GetProperty("counter").GetInt32().Should().Be(2);
+ Assert.NotNull(firstSnapshot);
+ Assert.Equal(2, firstSnapshot!.Snapshot.GetProperty("counter").GetInt32());
ChatMessage secondUserMessage = new(ChatRole.User, "increment again");
@@ -158,8 +157,8 @@ public async Task StateSnapshot_CanBeUsedInSubsequentRequest_ForStateRoundTripAs
// Assert - Second round should have incremented counter again.
StateSnapshotEvent? secondSnapshot = FindStateSnapshot(secondRoundUpdates);
- secondSnapshot.Should().NotBeNull();
- secondSnapshot!.Snapshot.GetProperty("counter").GetInt32().Should().Be(3, "counter should be incremented twice: 1 -> 2 -> 3");
+ Assert.NotNull(secondSnapshot);
+ Assert.Equal(3, secondSnapshot!.Snapshot.GetProperty("counter").GetInt32());
}
[Fact]
@@ -182,9 +181,9 @@ public async Task WithoutState_AgentBehavesNormally_NoStateSnapshotReturnedAsync
}
// Assert
- updates.Should().NotBeEmpty();
- FindStateSnapshot(updates).Should().BeNull("should not return state snapshot when no state is provided");
- updates.Should().Contain(u => u.Contents.Any(c => c is TextContent));
+ Assert.NotEmpty(updates);
+ Assert.Null(FindStateSnapshot(updates));
+ Assert.Contains(updates, u => u.Contents.Any(c => c is TextContent));
}
[Fact]
@@ -208,9 +207,9 @@ public async Task EmptyState_DoesNotTriggerStateHandlingAsync()
}
// Assert - empty state {} should be treated as no state.
- updates.Should().NotBeEmpty();
- FindStateSnapshot(updates).Should().BeNull("empty state should be treated as no state");
- updates.Should().Contain(u => u.Contents.Any(c => c is TextContent));
+ Assert.NotEmpty(updates);
+ Assert.Null(FindStateSnapshot(updates));
+ Assert.Contains(updates, u => u.Contents.Any(c => c is TextContent));
}
[Fact]
@@ -232,9 +231,9 @@ public async Task NonStreamingRunAsync_WithState_ReturnsTextResponseAsync()
// content-less STATE_SNAPSHOT update (Microsoft.Extensions.AI only materializes updates that carry
// content), so the non-streaming path surfaces the aggregated text response. The state round-trip
// itself is verified by the streaming tests above.
- response.Should().NotBeNull();
- response.Messages.Should().NotBeEmpty();
- response.Text.Should().Contain("State processed");
+ Assert.NotNull(response);
+ Assert.NotEmpty(response.Messages);
+ Assert.Contains("State processed", response.Text);
}
private ChatClientAgent CreateAgent()
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs
index 948a4bb9a36..b19ed3b9c92 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs
@@ -10,7 +10,6 @@
using System.Threading;
using System.Threading.Tasks;
using AGUI.Client;
-using FluentAssertions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.TestHost;
@@ -56,18 +55,18 @@ public async Task ServerTriggersSingleFunctionCallAsync()
}
// Assert
- callCount.Should().Be(1, "server function should be called once");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionCallContent), "should contain function call");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionResultContent), "should contain function result");
+ Assert.Equal(1, callCount);
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionCallContent));
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionResultContent));
var functionCallUpdates = updates.Where(u => u.Contents.Any(c => c is FunctionCallContent)).ToList();
- functionCallUpdates.Should().HaveCount(1);
+ Assert.Single(functionCallUpdates ?? []);
var functionResultUpdates = updates.Where(u => u.Contents.Any(c => c is FunctionResultContent)).ToList();
- functionResultUpdates.Should().HaveCount(1);
+ Assert.Single(functionResultUpdates ?? []);
- var resultContent = functionResultUpdates[0].Contents.OfType().First();
- resultContent.Result.Should().NotBeNull();
+ FunctionResultContent resultContent = Assert.Single(updates.SelectMany(u => u.Contents.OfType()));
+ Assert.NotNull(resultContent.Result);
}
[Fact]
@@ -104,19 +103,19 @@ public async Task ServerTriggersMultipleFunctionCallsAsync()
}
// Assert
- getWeatherCallCount.Should().Be(1, "GetWeather should be called once");
- getTimeCallCount.Should().Be(1, "GetTime should be called once");
+ Assert.Equal(1, getWeatherCallCount);
+ Assert.Equal(1, getTimeCallCount);
var functionCallUpdates = updates.Where(u => u.Contents.Any(c => c is FunctionCallContent)).ToList();
- functionCallUpdates.Should().NotBeEmpty("should contain function calls");
+ Assert.NotEmpty(functionCallUpdates);
var functionCalls = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionCalls.Should().HaveCount(2, "should have 2 function calls");
- functionCalls.Should().Contain(fc => fc.Name == "GetWeather");
- functionCalls.Should().Contain(fc => fc.Name == "GetTime");
+ Assert.Equal(2, functionCalls.Count);
+ Assert.Contains(functionCalls, fc => fc.Name == "GetWeather");
+ Assert.Contains(functionCalls, fc => fc.Name == "GetTime");
var functionResults = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionResults.Should().HaveCount(2, "should have 2 function results");
+ Assert.Equal(2, functionResults.Count);
}
[Fact]
@@ -145,18 +144,18 @@ public async Task ClientTriggersSingleFunctionCallAsync()
}
// Assert
- callCount.Should().Be(1, "client function should be called once");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionCallContent), "should contain function call");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionResultContent), "should contain function result");
+ Assert.Equal(1, callCount);
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionCallContent));
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionResultContent));
var functionCallUpdates = updates.Where(u => u.Contents.Any(c => c is FunctionCallContent)).ToList();
- functionCallUpdates.Should().HaveCount(1);
+ Assert.Single(functionCallUpdates ?? []);
var functionResultUpdates = updates.Where(u => u.Contents.Any(c => c is FunctionResultContent)).ToList();
- functionResultUpdates.Should().HaveCount(1);
+ Assert.Single(functionResultUpdates ?? []);
- var resultContent = functionResultUpdates[0].Contents.OfType().First();
- resultContent.Result.Should().NotBeNull();
+ FunctionResultContent resultContent = Assert.Single(updates.SelectMany(u => u.Contents.OfType()));
+ Assert.NotNull(resultContent.Result);
}
[Fact]
@@ -193,19 +192,19 @@ public async Task ClientTriggersMultipleFunctionCallsAsync()
}
// Assert
- calculateCallCount.Should().Be(1, "Calculate should be called once");
- formatCallCount.Should().Be(1, "FormatText should be called once");
+ Assert.Equal(1, calculateCallCount);
+ Assert.Equal(1, formatCallCount);
var functionCallUpdates = updates.Where(u => u.Contents.Any(c => c is FunctionCallContent)).ToList();
- functionCallUpdates.Should().NotBeEmpty("should contain function calls");
+ Assert.NotEmpty(functionCallUpdates);
var functionCalls = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionCalls.Should().HaveCount(2, "should have 2 function calls");
- functionCalls.Should().Contain(fc => fc.Name == "Calculate");
- functionCalls.Should().Contain(fc => fc.Name == "FormatText");
+ Assert.Equal(2, functionCalls.Count);
+ Assert.Contains(functionCalls, fc => fc.Name == "Calculate");
+ Assert.Contains(functionCalls, fc => fc.Name == "FormatText");
var functionResults = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionResults.Should().HaveCount(2, "should have 2 function results");
+ Assert.Equal(2, functionResults.Count);
}
[Fact]
@@ -263,29 +262,29 @@ public async Task ServerAndClientTriggerFunctionCallsSimultaneouslyAsync()
// the streaming pipeline. This is now correct behavior thanks to
// ConfigureForMixedInvocation in the AGUI.Hosting.AspNetCore package.
- serverCallCount.Should().Be(1, "server function should execute on server");
- clientCallCount.Should().Be(1, "client function should execute on client");
+ Assert.Equal(1, serverCallCount);
+ Assert.Equal(1, clientCallCount);
var functionCallUpdates = updates.Where(u => u.Contents.Any(c => c is FunctionCallContent)).ToList();
- functionCallUpdates.Should().NotBeEmpty("should contain function calls");
+ Assert.NotEmpty(functionCallUpdates);
var functionCalls = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionCalls.Should().HaveCount(2, "should have 2 function calls");
- functionCalls.Should().Contain(fc => fc.Name == "GetServerData");
- functionCalls.Should().Contain(fc => fc.Name == "GetClientData");
+ Assert.Equal(2, functionCalls.Count);
+ Assert.Contains(functionCalls, fc => fc.Name == "GetServerData");
+ Assert.Contains(functionCalls, fc => fc.Name == "GetClientData");
var functionResults = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionResults.Should().HaveCount(2, "both server and client function results should be present");
+ Assert.Equal(2, functionResults.Count);
- var serverResult = functionResults.FirstOrDefault(fr =>
+ FunctionResultContent? serverResult = functionResults.FirstOrDefault(fr =>
functionCalls.Any(fc => fc.Name == "GetServerData" && fc.CallId == fr.CallId));
- serverResult.Should().NotBeNull("server function call should have a result");
- serverResult!.Result?.ToString().Should().Contain("Server data");
+ Assert.NotNull(serverResult);
+ Assert.Contains("Server data", serverResult!.Result?.ToString() ?? string.Empty);
- var clientResult = functionResults.FirstOrDefault(fr =>
+ FunctionResultContent? clientResult = functionResults.FirstOrDefault(fr =>
functionCalls.Any(fc => fc.Name == "GetClientData" && fc.CallId == fr.CallId));
- clientResult.Should().NotBeNull("client function call should have a result");
- clientResult!.Result?.ToString().Should().Contain("Client data");
+ Assert.NotNull(clientResult);
+ Assert.Contains("Client data", clientResult!.Result?.ToString() ?? string.Empty);
}
[Fact]
@@ -310,13 +309,13 @@ public async Task FunctionCallsPreserveCallIdAndNameAsync()
// Assert
var functionCallContent = updates.SelectMany(u => u.Contents.OfType()).FirstOrDefault();
- functionCallContent.Should().NotBeNull();
- functionCallContent!.CallId.Should().NotBeNullOrEmpty();
- functionCallContent.Name.Should().Be("TestFunction");
+ Assert.NotNull(functionCallContent);
+ Assert.False(string.IsNullOrEmpty(functionCallContent!.CallId));
+ Assert.Equal("TestFunction", functionCallContent.Name);
var functionResultContent = updates.SelectMany(u => u.Contents.OfType()).FirstOrDefault();
- functionResultContent.Should().NotBeNull();
- functionResultContent!.CallId.Should().Be(functionCallContent.CallId, "result should have same call ID as the call");
+ Assert.NotNull(functionResultContent);
+ Assert.Equal(functionCallContent.CallId, functionResultContent!.CallId);
}
[Fact]
@@ -353,20 +352,21 @@ public async Task ParallelFunctionCallsFromServerAreHandledCorrectlyAsync()
}
// Assert
- func1CallCount.Should().Be(1, "Function1 should be called once");
- func2CallCount.Should().Be(1, "Function2 should be called once");
+ Assert.Equal(1, func1CallCount);
+ Assert.Equal(1, func2CallCount);
var functionCalls = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionCalls.Should().HaveCount(2);
- functionCalls.Select(fc => fc.Name).Should().Contain(s_expectedFunctionNames);
+ Assert.Equal(2, functionCalls.Count);
+ string[] functionNames = [.. functionCalls.Select(fc => fc.Name)];
+ Assert.All(s_expectedFunctionNames, expectedName => Assert.Contains(expectedName, functionNames));
var functionResults = updates.SelectMany(u => u.Contents.OfType()).ToList();
- functionResults.Should().HaveCount(2);
+ Assert.Equal(2, functionResults.Count);
// Each result should match its corresponding call ID
foreach (var call in functionCalls)
{
- functionResults.Should().Contain(r => r.CallId == call.CallId);
+ Assert.Contains(functionResults, r => r.CallId == call.CallId);
}
}
@@ -396,9 +396,9 @@ public async Task AGUIChatClientCombinesCustomJsonSerializerOptionsAsync()
// Assert
var jsonElement = JsonElement.Parse(json);
- jsonElement.GetProperty("MaxTemp").GetInt32().Should().Be(75);
- jsonElement.GetProperty("MinTemp").GetInt32().Should().Be(60);
- jsonElement.GetProperty("Outlook").GetString().Should().Be("Rainy");
+ Assert.Equal(75, jsonElement.GetProperty("MaxTemp").GetInt32());
+ Assert.Equal(60, jsonElement.GetProperty("MinTemp").GetInt32());
+ Assert.Equal("Rainy", jsonElement.GetProperty("Outlook").GetString());
this._output.WriteLine("Successfully serialized custom type: " + json);
@@ -439,17 +439,17 @@ public async Task ServerToolCallWithCustomArgumentsAsync()
}
// Assert
- callCount.Should().Be(1, "server function with custom arguments should be called once");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionCallContent), "should contain function call");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionResultContent), "should contain function result");
+ Assert.Equal(1, callCount);
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionCallContent));
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionResultContent));
var functionCallContent = updates.SelectMany(u => u.Contents.OfType()).FirstOrDefault();
- functionCallContent.Should().NotBeNull();
- functionCallContent!.Name.Should().Be("GetServerForecast");
+ Assert.NotNull(functionCallContent);
+ Assert.Equal("GetServerForecast", functionCallContent!.Name);
var functionResultContent = updates.SelectMany(u => u.Contents.OfType()).FirstOrDefault();
- functionResultContent.Should().NotBeNull();
- functionResultContent!.Result.Should().NotBeNull();
+ Assert.NotNull(functionResultContent);
+ Assert.NotNull(functionResultContent!.Result);
}
[Fact]
@@ -485,17 +485,17 @@ public async Task ClientToolCallWithCustomArgumentsAsync()
}
// Assert
- callCount.Should().Be(1, "client function with custom arguments should be called once");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionCallContent), "should contain function call");
- updates.Should().Contain(u => u.Contents.Any(c => c is FunctionResultContent), "should contain function result");
+ Assert.Equal(1, callCount);
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionCallContent));
+ Assert.Contains(updates, u => u.Contents.Any(c => c is FunctionResultContent));
var functionCallContent = updates.SelectMany(u => u.Contents.OfType()).FirstOrDefault();
- functionCallContent.Should().NotBeNull();
- functionCallContent!.Name.Should().Be("GetClientForecast");
+ Assert.NotNull(functionCallContent);
+ Assert.Equal("GetClientForecast", functionCallContent!.Name);
var functionResultContent = updates.SelectMany(u => u.Contents.OfType()).FirstOrDefault();
- functionResultContent.Should().NotBeNull();
- functionResultContent!.Result.Should().NotBeNull();
+ Assert.NotNull(functionResultContent);
+ Assert.NotNull(functionResultContent!.Result);
}
private async Task SetupTestServerAsync(
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ConfigureAGUIJsonOptionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ConfigureAGUIJsonOptionsTests.cs
index 9ffe491bf63..88ada833871 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ConfigureAGUIJsonOptionsTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ConfigureAGUIJsonOptionsTests.cs
@@ -2,7 +2,6 @@
using System.Text.Json;
using AGUI.Abstractions;
-using FluentAssertions;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@@ -21,7 +20,7 @@ public void AddAGUIServer_ConfiguresJsonOptions_ResolvesAGUIWireTypes()
// The AG-UI wire context must be in the resolver chain (needed on the net10
// TypedResults.ServerSentEvents path, which serializes events through these options).
- options.Invoking(o => o.GetTypeInfo(typeof(RunStartedEvent))).Should().NotThrow();
+ Assert.Null(Record.Exception(() => options.GetTypeInfo(typeof(RunStartedEvent))));
}
[Fact]
@@ -30,7 +29,7 @@ public void AddAGUIServer_ConfiguresJsonOptions_ResolvesAgentAbstractionsTypes()
JsonSerializerOptions options = BuildConfiguredSerializerOptions();
// The Agent Framework abstractions resolver must also be present so M.E.AI types resolve.
- options.Invoking(o => o.GetTypeInfo(typeof(ChatMessage))).Should().NotThrow();
+ Assert.Null(Record.Exception(() => options.GetTypeInfo(typeof(ChatMessage))));
}
private static JsonSerializerOptions BuildConfiguredSerializerOptions()
diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj
index ed65db63289..8497c2d761d 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj
+++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj
@@ -5,7 +5,6 @@
-
diff --git a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/ListAgentToolsWithTasksTests.cs b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/ListAgentToolsWithTasksTests.cs
index 1c3c9695047..9cb92dbc435 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/ListAgentToolsWithTasksTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/ListAgentToolsWithTasksTests.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
using System.Threading.Tasks;
-using FluentAssertions;
using ModelContextProtocol.Server;
namespace Microsoft.Agents.AI.Mcp.UnitTests;
@@ -24,9 +23,9 @@ public async Task ListAgentToolsWithTasks_WrapsAllToolsAsync()
var result = await fixture.Client.ListAgentToolsWithTasksAsync();
// Assert
- result.Should().HaveCount(2);
- result.Should().AllBeOfType();
- result.Select(tool => tool.Name).Should().Equal("first", "second");
+ Assert.Equal(2, result.Count);
+ Assert.All(result, tool => Assert.IsType(tool));
+ Assert.Equal(["first", "second"], result.Select(tool => tool.Name));
}
[Fact]
@@ -36,10 +35,10 @@ public async Task ListAgentToolsWithTasks_ThrowsOnNullClientAsync()
ModelContextProtocol.Client.McpClient client = null!;
// Act
- Func act = async () => await client.ListAgentToolsWithTasksAsync();
+ async Task actAsync() => await client.ListAgentToolsWithTasksAsync();
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -53,10 +52,10 @@ public async Task ListAgentToolsWithTasks_NonPositiveStuckPollLimit_ThrowsAsync(
var options = new McpTaskOptions { MaxConsecutiveStuckPolls = 0 };
// Act
- Func act = async () => await fixture.Client.ListAgentToolsWithTasksAsync(options);
+ async Task actAsync() => await fixture.Client.ListAgentToolsWithTasksAsync(options);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -70,10 +69,10 @@ public async Task ListAgentToolsWithTasks_NonPositiveInputRequestLimit_ThrowsAsy
var options = new McpTaskOptions { MaxTotalInputRequests = 0 };
// Act
- Func act = async () => await fixture.Client.ListAgentToolsWithTasksAsync(options);
+ async Task actAsync() => await fixture.Client.ListAgentToolsWithTasksAsync(options);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -87,10 +86,10 @@ public async Task ListAgentToolsWithTasks_NonPositiveCancellationTimeout_ThrowsA
var options = new McpTaskOptions { RemoteCancellationTimeout = TimeSpan.Zero };
// Act
- Func act = async () => await fixture.Client.ListAgentToolsWithTasksAsync(options);
+ async Task actAsync() => await fixture.Client.ListAgentToolsWithTasksAsync(options);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -104,10 +103,10 @@ public async Task ListAgentToolsWithTasks_SubMillisecondCancellationTimeout_Thro
var options = new McpTaskOptions { RemoteCancellationTimeout = TimeSpan.FromTicks(1) };
// Act
- Func act = async () => await fixture.Client.ListAgentToolsWithTasksAsync(options);
+ async Task actAsync() => await fixture.Client.ListAgentToolsWithTasksAsync(options);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -125,10 +124,10 @@ public async Task ListAgentToolsWithTasks_InvalidPollingIntervalRange_ThrowsAsyn
};
// Act
- Func act = async () => await fixture.Client.ListAgentToolsWithTasksAsync(options);
+ async Task actAsync() => await fixture.Client.ListAgentToolsWithTasksAsync(options);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -146,10 +145,10 @@ public async Task ListAgentToolsWithTasks_PollingRangeWithoutWholeMillisecond_Th
};
// Act
- Func act = async () => await fixture.Client.ListAgentToolsWithTasksAsync(options);
+ async Task actAsync() => await fixture.Client.ListAgentToolsWithTasksAsync(options);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -166,9 +165,9 @@ public async Task ListAgentToolsWithTasks_PollingMaximumAboveRuntimeLimit_Throws
};
// Act
- Func act = async () => await fixture.Client.ListAgentToolsWithTasksAsync(options);
+ async Task actAsync() => await fixture.Client.ListAgentToolsWithTasksAsync(options);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
}
diff --git a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/McpTaskOptionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/McpTaskOptionsTests.cs
index 19b3eee9bef..30c85e750ca 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/McpTaskOptionsTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/McpTaskOptionsTests.cs
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
-using FluentAssertions;
namespace Microsoft.Agents.AI.Mcp.UnitTests;
@@ -14,11 +13,11 @@ public void Defaults_AreSane()
McpTaskOptions options = new();
// Assert
- options.CancelRemoteTaskOnLocalCancellation.Should().BeTrue();
- options.MaxConsecutiveStuckPolls.Should().Be(60);
- options.MaxTotalInputRequests.Should().Be(100);
- options.RemoteCancellationTimeout.Should().Be(TimeSpan.FromSeconds(5));
- options.MinimumPollingInterval.Should().Be(TimeSpan.FromMilliseconds(10));
- options.MaximumPollingInterval.Should().Be(TimeSpan.FromMilliseconds(uint.MaxValue - 1L));
+ Assert.True(options.CancelRemoteTaskOnLocalCancellation);
+ Assert.Equal(60, options.MaxConsecutiveStuckPolls);
+ Assert.Equal(100, options.MaxTotalInputRequests);
+ Assert.Equal(TimeSpan.FromSeconds(5), options.RemoteCancellationTimeout);
+ Assert.Equal(TimeSpan.FromMilliseconds(10), options.MinimumPollingInterval);
+ Assert.Equal(TimeSpan.FromMilliseconds(uint.MaxValue - 1L), options.MaximumPollingInterval);
}
}
diff --git a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/Microsoft.Agents.AI.Mcp.UnitTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/Microsoft.Agents.AI.Mcp.UnitTests.csproj
index d5763b5e379..843b21f28d6 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/Microsoft.Agents.AI.Mcp.UnitTests.csproj
+++ b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/Microsoft.Agents.AI.Mcp.UnitTests.csproj
@@ -6,7 +6,6 @@
-
diff --git a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/TaskAwareMcpClientAIFunctionTests.cs b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/TaskAwareMcpClientAIFunctionTests.cs
index 354e66390a4..9e101a899a0 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/TaskAwareMcpClientAIFunctionTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Mcp.UnitTests/TaskAwareMcpClientAIFunctionTests.cs
@@ -6,7 +6,6 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
@@ -34,10 +33,9 @@ public async Task InvokeAsync_TaskBackedTool_ReturnsResultAsync()
object? result = await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- result.Should().BeOfType()
- .Which.Text.Should().Be("task-result");
- fixture.CreatedTaskCount.Should().Be(1);
- fixture.PollCount.Should().BeGreaterThan(0);
+ Assert.Equal("task-result", Assert.IsType(result).Text);
+ Assert.Equal(1, fixture.CreatedTaskCount);
+ Assert.True(fixture.PollCount > 0);
}
[Theory]
@@ -62,14 +60,14 @@ public async Task InvokeAsync_InvalidInitialPollInterval_CancelsRemoteTaskAsync(
AIFunction wrapped = (await fixture.Client.ListAgentToolsWithTasksAsync()).Single();
// Act
- Func act = async () => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
+ async Task actAsync() => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage($"*pollIntervalMs of {pollIntervalMs}*");
+ ModelContextProtocol.McpException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Contains($"pollIntervalMs of {pollIntervalMs}", exception.Message);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -91,14 +89,14 @@ public async Task InvokeAsync_InvalidUpdatedPollInterval_CancelsRemoteTaskAsync(
AIFunction wrapped = (await fixture.Client.ListAgentToolsWithTasksAsync()).Single();
// Act
- Func act = async () => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
+ async Task actAsync() => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("*pollIntervalMs of 0*");
+ ModelContextProtocol.McpException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Contains("pollIntervalMs of 0", exception.Message);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -135,7 +133,7 @@ public async Task InvokeAsync_ConfiguredPollingRange_AcceptsShortServerIntervalA
object? result = await invocation;
// Assert
- result.Should().BeOfType().Which.Text.Should().Be("completed");
+ Assert.Equal("completed", Assert.IsType(result).Text);
}
finally
{
@@ -176,7 +174,7 @@ public async Task InvokeAsync_MissingPollInterval_ConstrainsFallbackToConfigured
object? result = await invocation;
// Assert
- result.Should().BeOfType().Which.Text.Should().Be("completed");
+ Assert.Equal("completed", Assert.IsType(result).Text);
}
finally
{
@@ -198,9 +196,8 @@ public async Task InvokeAsync_ServerWithoutTasks_ReturnsInlineResultAsync()
object? result = await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- result.Should().BeOfType()
- .Which.Text.Should().Be("inline-result");
- fixture.CreatedTaskCount.Should().Be(0);
+ Assert.Equal("inline-result", Assert.IsType(result).Text);
+ Assert.Equal(0, fixture.CreatedTaskCount);
}
[Fact]
@@ -247,10 +244,9 @@ public async Task InvokeAsync_InputRequired_DispatchesClientHandlerAsync()
object? result = await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- result.Should().BeOfType()
- .Which.Text.Should().Be("accept:yes");
- fixture.CreatedTaskCount.Should().Be(1);
- fixture.InputRequestCount.Should().Be(1);
+ Assert.Equal("accept:yes", Assert.IsType(result).Text);
+ Assert.Equal(1, fixture.CreatedTaskCount);
+ Assert.Equal(1, fixture.InputRequestCount);
}
[Fact]
@@ -284,10 +280,10 @@ public async Task InvokeAsync_ForwardsNullPrimitiveAndComplexArgumentsAsync()
_ = await wrapped.InvokeAsync(arguments, CancellationToken.None);
// Assert
- observedArguments.Should().NotBeNull();
- observedArguments!["optional"].ValueKind.Should().Be(JsonValueKind.Null);
- observedArguments["count"].GetInt32().Should().Be(3);
- observedArguments["payload"].GetProperty("label").GetString().Should().Be("nested");
+ Assert.NotNull(observedArguments);
+ Assert.Equal(JsonValueKind.Null, observedArguments!["optional"].ValueKind);
+ Assert.Equal(3, observedArguments["count"].GetInt32());
+ Assert.Equal("nested", observedArguments["payload"].GetProperty("label").GetString());
}
[Fact]
@@ -306,7 +302,7 @@ public async Task InvokeAsync_SimpleResult_MatchesMcpClientToolProjectionAsync()
object? wrappedResult = await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- wrappedResult.Should().BeEquivalentTo(innerResult);
+ Assert.Equivalent(innerResult, wrappedResult);
}
[Fact]
@@ -329,9 +325,9 @@ public async Task InvokeAsync_ToolError_PreservesCallToolResultEnvelopeAsync()
object? result = await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- JsonElement payload = result.Should().BeOfType().Subject;
- payload.GetProperty("isError").GetBoolean().Should().BeTrue();
- payload.GetProperty("content")[0].GetProperty("text").GetString().Should().Be("tool failed");
+ JsonElement payload = Assert.IsType(result);
+ Assert.True(payload.GetProperty("isError").GetBoolean());
+ Assert.Equal("tool failed", payload.GetProperty("content")[0].GetProperty("text").GetString());
}
[Fact]
@@ -359,13 +355,13 @@ await fixture.FailLatestTaskAsync(
JsonSerializer.SerializeToElement(new { code = -32603, message = "simulated failure" }));
// Act
- Func act = async () => await invocation;
+ async Task actAsync() => await invocation;
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("*simulated failure*");
- fixture.SuccessfulCancellationTransitionCount.Should().Be(0);
- fixture.CancellationRequestCount.Should().Be(0);
+ ModelContextProtocol.McpException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Contains("simulated failure", exception.Message);
+ Assert.Equal(0, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(0, fixture.CancellationRequestCount);
}
finally
{
@@ -397,13 +393,13 @@ public async Task InvokeAsync_ServerCancelledTask_ThrowsOperationCanceledAsync()
await fixture.CancelLatestTaskAsync();
// Act
- Func act = async () => await invocation;
+ async Task actAsync() => await invocation;
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("*cancelled by the server*");
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(0);
+ OperationCanceledException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Contains("cancelled by the server", exception.Message);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(0, fixture.CancellationRequestCount);
}
finally
{
@@ -443,14 +439,14 @@ public async Task InvokeAsync_InputHandlerFailure_CancelsRemoteTaskAsync()
AIFunction wrapped = (await fixture.Client.ListAgentToolsWithTasksAsync()).Single();
// Act
- Func act = async () => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
+ async Task actAsync() => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("input handler failed");
+ InvalidOperationException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Equal("input handler failed", exception.Message);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -472,14 +468,14 @@ public async Task InvokeAsync_GetTaskFailure_CancelsRemoteTaskAndPreservesProtoc
AIFunction wrapped = (await fixture.Client.ListAgentToolsWithTasksAsync()).Single();
// Act
- Func act = async () => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
+ async Task actAsync() => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("Request failed (remote): An error occurred.");
+ ModelContextProtocol.McpProtocolException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Equal("Request failed (remote): An error occurred.", exception.Message);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -515,14 +511,14 @@ public async Task InvokeAsync_UpdateTaskFailure_CancelsRemoteTaskAndPreservesPro
AIFunction wrapped = (await fixture.Client.ListAgentToolsWithTasksAsync()).Single();
// Act
- Func act = async () => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
+ async Task actAsync() => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("Request failed (remote): An error occurred.");
+ ModelContextProtocol.McpProtocolException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Equal("Request failed (remote): An error occurred.", exception.Message);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -549,12 +545,12 @@ public async Task InvokeAsync_MalformedCompletedResult_DoesNotCancelTerminalTask
await fixture.CompleteLatestTaskAsync(JsonSerializer.SerializeToElement("malformed"));
// Act
- Func act = async () => await invocation;
+ async Task actAsync() => await invocation;
// Assert
- await act.Should().ThrowAsync();
- fixture.SuccessfulCancellationTransitionCount.Should().Be(0);
- fixture.CancellationRequestCount.Should().Be(0);
+ await Assert.ThrowsAsync(actAsync);
+ Assert.Equal(0, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(0, fixture.CancellationRequestCount);
}
finally
{
@@ -596,14 +592,14 @@ public async Task InvokeAsync_StuckInputRequired_CancelsRemoteTaskAsync()
AIFunction wrapped = (await fixture.Client.ListAgentToolsWithTasksAsync(options)).Single();
// Act
- Func act = async () => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
+ async Task actAsync() => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("*2 consecutive polls*");
+ ModelContextProtocol.McpException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Contains("2 consecutive polls", exception.Message);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -650,10 +646,10 @@ public async Task InvokeAsync_InputRequestsAtLimit_CompletesAsync()
object? result = await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- result.Should().BeOfType().Which.Text.Should().Be("completed");
- handledInputRequests.Should().Be(2);
- fixture.SuccessfulCancellationTransitionCount.Should().Be(0);
- fixture.CancellationRequestCount.Should().Be(0);
+ Assert.Equal("completed", Assert.IsType(result).Text);
+ Assert.Equal(2, handledInputRequests);
+ Assert.Equal(0, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(0, fixture.CancellationRequestCount);
}
[Fact]
@@ -697,15 +693,15 @@ public async Task InvokeAsync_InputRequestLimitExceeded_CancelsBeforeDispatchAsy
AIFunction wrapped = (await fixture.Client.ListAgentToolsWithTasksAsync(options)).Single();
// Act
- Func act = async () => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
+ async Task actAsync() => await wrapped.InvokeAsync(arguments: null, CancellationToken.None);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("*limit of 2 unique input requests*");
- handledInputRequests.Should().Be(2);
+ ModelContextProtocol.McpException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Contains("limit of 2 unique input requests", exception.Message);
+ Assert.Equal(2, handledInputRequests);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -739,16 +735,16 @@ public async Task InvokeAsync_LocalCancellation_CancelsRemoteTaskAsync()
// Act
cts.Cancel();
- Func act = async () => await invocation;
+ async Task actAsync() => await invocation;
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAnyAsync(actAsync);
await fixture.RemoteCancellationObserved.WaitAsync(TimeSpan.FromSeconds(5));
await serverCancelled.Task.WaitAsync(TimeSpan.FromSeconds(5));
- fixture.CreatedTaskCount.Should().Be(1);
- fixture.PollCount.Should().BeGreaterThan(0);
- fixture.SuccessfulCancellationTransitionCount.Should().Be(1);
- fixture.CancellationRequestCount.Should().Be(1);
+ Assert.Equal(1, fixture.CreatedTaskCount);
+ Assert.True(fixture.PollCount > 0);
+ Assert.Equal(1, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(1, fixture.CancellationRequestCount);
}
[Fact]
@@ -777,12 +773,12 @@ public async Task InvokeAsync_LocalCancellation_DoesNotCancelRemoteTaskWhenDisab
// Act
cts.Cancel();
- Func act = async () => await invocation;
+ async Task actAsync() => await invocation;
// Assert
- await act.Should().ThrowAsync();
- fixture.SuccessfulCancellationTransitionCount.Should().Be(0);
- fixture.CancellationRequestCount.Should().Be(0);
+ await Assert.ThrowsAnyAsync(actAsync);
+ Assert.Equal(0, fixture.SuccessfulCancellationTransitionCount);
+ Assert.Equal(0, fixture.CancellationRequestCount);
}
finally
{
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/DefaultMcpToolHandlerTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/DefaultMcpToolHandlerTests.cs
index d6471e5d5a3..5a5b318f055 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/DefaultMcpToolHandlerTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/DefaultMcpToolHandlerTests.cs
@@ -7,7 +7,6 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Protocol;
@@ -27,7 +26,7 @@ public async Task Constructor_WithNoParameters_ShouldCreateInstanceAsync()
DefaultMcpToolHandler handler = new();
// Assert
- handler.Should().NotBeNull();
+ Assert.NotNull(handler);
await handler.DisposeAsync();
}
@@ -38,7 +37,7 @@ public async Task Constructor_WithNullHttpClientProvider_ShouldCreateInstanceAsy
DefaultMcpToolHandler handler = new(httpClientProvider: null);
// Assert
- handler.Should().NotBeNull();
+ Assert.NotNull(handler);
await handler.DisposeAsync();
}
@@ -52,7 +51,7 @@ public async Task Constructor_WithHttpClientProvider_ShouldCreateInstanceAsync()
DefaultMcpToolHandler handler = new(httpClientProvider: ProviderAsync);
// Assert
- handler.Should().NotBeNull();
+ Assert.NotNull(handler);
await handler.DisposeAsync();
}
@@ -67,10 +66,10 @@ public async Task DisposeAsync_WhenCalled_ShouldCompleteWithoutErrorAsync()
DefaultMcpToolHandler handler = new();
// Act
- Func act = async () => await handler.DisposeAsync();
+ async Task actAsync() => await handler.DisposeAsync();
// Assert
- await act.Should().NotThrowAsync();
+ Assert.Null(await Record.ExceptionAsync(actAsync));
}
[Fact]
@@ -81,10 +80,10 @@ public async Task DisposeAsync_WhenCalledMultipleTimes_ShouldHandleGracefullyAsy
// Act
await handler.DisposeAsync();
- Func act = async () => await handler.DisposeAsync();
+ async Task actAsync() => await handler.DisposeAsync();
// Assert - Second dispose should throw ObjectDisposedException from the semaphore
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
#endregion
@@ -128,8 +127,8 @@ await handler.InvokeToolAsync(
}
// Assert
- providerCalled.Should().BeTrue();
- capturedServerUrl.Should().Be("http://localhost:12345/mcp");
+ Assert.True(providerCalled);
+ Assert.Equal("http://localhost:12345/mcp", capturedServerUrl);
}
[Fact]
@@ -170,7 +169,7 @@ await handler.InvokeToolAsync(
}
// Assert
- providerCalled.Should().BeTrue();
+ Assert.True(providerCalled);
}
#endregion
@@ -216,7 +215,7 @@ await handler.InvokeToolAsync(
}
// Assert - Provider is called each time because McpClient creation fails before caching
- providerCallCount.Should().Be(2);
+ Assert.Equal(2, providerCallCount);
}
finally
{
@@ -260,7 +259,7 @@ await handler.InvokeToolAsync(
}
// Assert - Provider should be called once per unique server URL
- providerCallCount.Should().Be(2);
+ Assert.Equal(2, providerCallCount);
}
finally
{
@@ -311,7 +310,7 @@ await handler.InvokeToolAsync(
}
// Assert - Different headers should create different cache keys
- providerCallCount.Should().Be(2);
+ Assert.Equal(2, providerCallCount);
}
finally
{
@@ -330,7 +329,7 @@ public void ComputeHeadersHash_WithNullHeaders_ReturnsEmptyString()
string result = DefaultMcpToolHandler.ComputeHeadersHash(null);
// Assert
- result.Should().BeEmpty();
+ Assert.Equal(string.Empty, result);
}
[Fact]
@@ -340,7 +339,7 @@ public void ComputeHeadersHash_WithEmptyHeaders_ReturnsEmptyString()
string result = DefaultMcpToolHandler.ComputeHeadersHash(new Dictionary());
// Assert
- result.Should().BeEmpty();
+ Assert.Equal(string.Empty, result);
}
[Fact]
@@ -363,7 +362,7 @@ public void ComputeHeadersHash_SameHeadersDifferentOrder_ReturnsSameHash()
string hash2 = DefaultMcpToolHandler.ComputeHeadersHash(headers2);
// Assert
- hash1.Should().Be(hash2);
+ Assert.Equal(hash2, hash1);
}
[Fact]
@@ -378,7 +377,7 @@ public void ComputeHeadersHash_SameKeysDifferentCaseKeys_ReturnsSameHash()
string hash2 = DefaultMcpToolHandler.ComputeHeadersHash(headers2);
// Assert
- hash1.Should().Be(hash2);
+ Assert.Equal(hash2, hash1);
}
[Fact]
@@ -393,7 +392,7 @@ public void ComputeHeadersHash_SameKeysDifferentCaseValues_ReturnsDifferentHash(
string hash2 = DefaultMcpToolHandler.ComputeHeadersHash(headers2);
// Assert
- hash1.Should().NotBe(hash2);
+ Assert.NotEqual(hash2, hash1);
}
[Fact]
@@ -408,7 +407,7 @@ public void ComputeHeadersHash_DifferentHeaders_ReturnsDifferentHash()
string hash2 = DefaultMcpToolHandler.ComputeHeadersHash(headers2);
// Assert
- hash1.Should().NotBe(hash2);
+ Assert.NotEqual(hash2, hash1);
}
#endregion
@@ -433,7 +432,7 @@ public void BuildCacheKey_SameInputs_ReturnsEqualKeys()
var key2 = DefaultMcpToolHandler.BuildCacheKey("http://localhost/mcp", "label", "conn", headers);
// Assert
- key1.Should().Be(key2);
+ Assert.Equal(key2, key1);
}
[Fact]
@@ -444,9 +443,9 @@ public void BuildCacheKey_DifferentConnectionName_ReturnsDifferentKeys()
var key2 = DefaultMcpToolHandler.BuildCacheKey("http://localhost/mcp", "label", "connection-b", null);
// Assert
- key1.Should().NotBe(key2);
- key1.Connection.Should().Be("connection-a");
- key2.Connection.Should().Be("connection-b");
+ Assert.NotEqual(key2, key1);
+ Assert.Equal("connection-a", key1.Connection);
+ Assert.Equal("connection-b", key2.Connection);
}
[Fact]
@@ -457,9 +456,9 @@ public void BuildCacheKey_DifferentServerLabel_ReturnsDifferentKeys()
var key2 = DefaultMcpToolHandler.BuildCacheKey("http://localhost/mcp", "label-b", null, null);
// Assert
- key1.Should().NotBe(key2);
- key1.Label.Should().Be("label-a");
- key2.Label.Should().Be("label-b");
+ Assert.NotEqual(key2, key1);
+ Assert.Equal("label-a", key1.Label);
+ Assert.Equal("label-b", key2.Label);
}
[Fact]
@@ -471,7 +470,7 @@ public void BuildCacheKey_CaseSensitiveUrlPath_ReturnsDifferentKeys()
var key2 = DefaultMcpToolHandler.BuildCacheKey("http://localhost/tools", null, null, null);
// Assert
- key1.Should().NotBe(key2);
+ Assert.NotEqual(key2, key1);
}
[Fact]
@@ -486,8 +485,8 @@ public void BuildCacheKey_HeaderValuesCaseSensitive_ReturnsDifferentKeys()
var key2 = DefaultMcpToolHandler.BuildCacheKey("http://localhost/mcp", null, null, headers2);
// Assert — header value case must propagate into the cache key
- key1.Should().NotBe(key2);
- key1.HeadersHash.Should().NotBe(key2.HeadersHash);
+ Assert.NotEqual(key2, key1);
+ Assert.NotEqual(key2.HeadersHash, key1.HeadersHash);
}
[Fact]
@@ -497,9 +496,9 @@ public void BuildCacheKey_NullLabelAndConnection_NormalizesToEmptyString()
var key = DefaultMcpToolHandler.BuildCacheKey("http://localhost/mcp", null, null, null);
// Assert — verifies null-safety contract callers rely on
- key.Label.Should().BeEmpty();
- key.Connection.Should().BeEmpty();
- key.HeadersHash.Should().BeEmpty();
+ Assert.Equal(string.Empty, key.Label);
+ Assert.Equal(string.Empty, key.Connection);
+ Assert.Equal(string.Empty, key.HeadersHash);
}
#endregion
@@ -513,7 +512,7 @@ public void IsListToolsToolName_WithReservedName_ShouldReturnTrue()
bool result = DefaultMcpToolHandler.IsListToolsToolName(DefaultMcpToolHandler.ListToolsToolName);
// Assert
- result.Should().BeTrue();
+ Assert.True(result);
}
[Fact]
@@ -523,7 +522,7 @@ public void IsListToolsToolName_WithRegularToolName_ShouldReturnFalse()
bool result = DefaultMcpToolHandler.IsListToolsToolName("search");
// Assert
- result.Should().BeFalse();
+ Assert.False(result);
}
[Fact]
@@ -535,7 +534,7 @@ public async Task InvokeToolAsync_WithListToolsArguments_ShouldThrowArgumentExce
try
{
// Act
- Func act = async () => await handler.InvokeToolAsync(
+ async Task actAsync() => await handler.InvokeToolAsync(
serverUrl: "http://localhost:12345/mcp",
serverLabel: "test",
toolName: DefaultMcpToolHandler.ListToolsToolName,
@@ -544,8 +543,8 @@ public async Task InvokeToolAsync_WithListToolsArguments_ShouldThrowArgumentExce
connectionName: null);
// Assert
- await act.Should().ThrowAsync()
- .WithMessage("*does not accept tool arguments*");
+ ArgumentException exception = await Assert.ThrowsAsync(actAsync);
+ Assert.Contains("does not accept tool arguments", exception.Message);
}
finally
{
@@ -580,12 +579,12 @@ public async Task CreateListToolsResultContent_WithTools_ShouldSerializeToolMeta
McpServerToolResultContent result = DefaultMcpToolHandler.CreateListToolsResultContent([tool]);
// Assert
- TextContent text = result.Outputs.Should().ContainSingle().Subject.Should().BeOfType().Subject;
+ TextContent text = Assert.IsType(Assert.Single(result.Outputs ?? []));
using JsonDocument document = JsonDocument.Parse(text.Text);
JsonElement listedTool = document.RootElement.GetProperty("tools")[0];
- listedTool.GetProperty("name").GetString().Should().Be("search");
- listedTool.GetProperty("description").GetString().Should().Be("Searches documentation.");
- listedTool.GetProperty("inputSchema").GetProperty("properties").GetProperty("query").GetProperty("type").GetString().Should().Be("string");
+ Assert.Equal("search", listedTool.GetProperty("name").GetString());
+ Assert.Equal("Searches documentation.", listedTool.GetProperty("description").GetString());
+ Assert.Equal("string", listedTool.GetProperty("inputSchema").GetProperty("properties").GetProperty("query").GetProperty("type").GetString());
}
#endregion
@@ -599,7 +598,7 @@ public async Task DefaultMcpToolHandler_ShouldImplementIMcpToolHandlerAsync()
DefaultMcpToolHandler handler = new();
// Assert
- handler.Should().BeAssignableTo();
+ Assert.IsAssignableFrom(handler);
await handler.DisposeAsync();
}
@@ -610,7 +609,7 @@ public async Task DefaultMcpToolHandler_ShouldImplementIAsyncDisposableAsync()
DefaultMcpToolHandler handler = new();
// Assert
- handler.Should().BeAssignableTo();
+ Assert.IsAssignableFrom(handler);
await handler.DisposeAsync();
}
@@ -628,9 +627,9 @@ public void ConvertContentBlock_TextContentBlock_ShouldReturnTextContent()
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- TextContent textContent = result.Should().BeOfType().Subject;
- textContent.Text.Should().Be("hello world");
- textContent.RawRepresentation.Should().BeSameAs(block);
+ TextContent textContent = Assert.IsType(result);
+ Assert.Equal("hello world", textContent.Text);
+ Assert.Same(block, textContent.RawRepresentation);
}
[Fact]
@@ -643,11 +642,11 @@ public void ConvertContentBlock_ImageContentBlock_WithEmptyData_ShouldReturnData
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- DataContent dataContent = result.Should().BeOfType().Subject;
- dataContent.MediaType.Should().Be("image/png");
- dataContent.Uri.Should().Be("data:image/png;base64,");
- dataContent.Data.IsEmpty.Should().BeTrue();
- dataContent.RawRepresentation.Should().BeSameAs(block);
+ DataContent dataContent = Assert.IsType(result);
+ Assert.Equal("image/png", dataContent.MediaType);
+ Assert.Equal("data:image/png;base64,", dataContent.Uri);
+ Assert.True(dataContent.Data.IsEmpty);
+ Assert.Same(block, dataContent.RawRepresentation);
}
[Fact]
@@ -663,11 +662,11 @@ public void ConvertContentBlock_ImageContentBlock_WithBase64Payload_ShouldReturn
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- DataContent dataContent = result.Should().BeOfType().Subject;
- dataContent.MediaType.Should().Be("image/png");
- dataContent.Data.ToArray().Should().BeEquivalentTo(expectedDecoded);
- dataContent.Uri.Should().Be($"data:image/png;base64,{Base64Payload}");
- dataContent.RawRepresentation.Should().BeSameAs(block);
+ DataContent dataContent = Assert.IsType(result);
+ Assert.Equal("image/png", dataContent.MediaType);
+ Assert.Equivalent(expectedDecoded, dataContent.Data.ToArray());
+ Assert.Equal($"data:image/png;base64,{Base64Payload}", dataContent.Uri);
+ Assert.Same(block, dataContent.RawRepresentation);
}
[Fact]
@@ -680,11 +679,11 @@ public void ConvertContentBlock_AudioContentBlock_WithEmptyData_ShouldReturnData
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- DataContent dataContent = result.Should().BeOfType().Subject;
- dataContent.MediaType.Should().Be("audio/wav");
- dataContent.Uri.Should().Be("data:audio/wav;base64,");
- dataContent.Data.IsEmpty.Should().BeTrue();
- dataContent.RawRepresentation.Should().BeSameAs(block);
+ DataContent dataContent = Assert.IsType(result);
+ Assert.Equal("audio/wav", dataContent.MediaType);
+ Assert.Equal("data:audio/wav;base64,", dataContent.Uri);
+ Assert.True(dataContent.Data.IsEmpty);
+ Assert.Same(block, dataContent.RawRepresentation);
}
[Fact]
@@ -700,11 +699,11 @@ public void ConvertContentBlock_AudioContentBlock_WithBase64Payload_ShouldReturn
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- DataContent dataContent = result.Should().BeOfType().Subject;
- dataContent.MediaType.Should().Be("audio/wav");
- dataContent.Data.ToArray().Should().BeEquivalentTo(expectedDecoded);
- dataContent.Uri.Should().Be($"data:audio/wav;base64,{Base64Payload}");
- dataContent.RawRepresentation.Should().BeSameAs(block);
+ DataContent dataContent = Assert.IsType(result);
+ Assert.Equal("audio/wav", dataContent.MediaType);
+ Assert.Equivalent(expectedDecoded, dataContent.Data.ToArray());
+ Assert.Equal($"data:audio/wav;base64,{Base64Payload}", dataContent.Uri);
+ Assert.Same(block, dataContent.RawRepresentation);
}
[Fact]
@@ -725,9 +724,9 @@ public void ConvertContentBlock_EmbeddedResourceBlock_WithTextResource_ShouldRet
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- TextContent textContent = result.Should().BeOfType().Subject;
- textContent.Text.Should().Be("embedded text payload");
- textContent.RawRepresentation.Should().BeSameAs(block);
+ TextContent textContent = Assert.IsType(result);
+ Assert.Equal("embedded text payload", textContent.Text);
+ Assert.Same(block, textContent.RawRepresentation);
}
[Fact]
@@ -751,11 +750,11 @@ public void ConvertContentBlock_EmbeddedResourceBlock_WithBlobResource_ShouldRet
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- DataContent dataContent = result.Should().BeOfType().Subject;
- dataContent.MediaType.Should().Be("application/zip");
- dataContent.Data.ToArray().Should().BeEquivalentTo(expectedDecoded);
- dataContent.Uri.Should().Be($"data:application/zip;base64,{Base64Payload}");
- dataContent.RawRepresentation.Should().BeSameAs(block);
+ DataContent dataContent = Assert.IsType(result);
+ Assert.Equal("application/zip", dataContent.MediaType);
+ Assert.Equivalent(expectedDecoded, dataContent.Data.ToArray());
+ Assert.Equal($"data:application/zip;base64,{Base64Payload}", dataContent.Uri);
+ Assert.Same(block, dataContent.RawRepresentation);
}
[Fact]
@@ -773,10 +772,10 @@ public void ConvertContentBlock_ResourceLinkBlock_WithUri_ShouldReturnUriContent
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- UriContent uriContent = result.Should().BeOfType().Subject;
- uriContent.Uri.ToString().Should().Be("https://example.com/resource.bin");
- uriContent.MediaType.Should().Be("application/zip");
- uriContent.RawRepresentation.Should().BeSameAs(block);
+ UriContent uriContent = Assert.IsType(result);
+ Assert.Equal("https://example.com/resource.bin", uriContent.Uri.ToString());
+ Assert.Equal("application/zip", uriContent.MediaType);
+ Assert.Same(block, uriContent.RawRepresentation);
}
[Fact]
@@ -794,9 +793,9 @@ public void ConvertContentBlock_ResourceLinkBlock_WithNullMimeType_ShouldDefault
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- UriContent uriContent = result.Should().BeOfType().Subject;
- uriContent.Uri.ToString().Should().Be("https://example.com/resource");
- uriContent.MediaType.Should().Be("application/octet-stream");
+ UriContent uriContent = Assert.IsType(result);
+ Assert.Equal("https://example.com/resource", uriContent.Uri.ToString());
+ Assert.Equal("application/octet-stream", uriContent.MediaType);
}
[Fact]
@@ -819,11 +818,11 @@ public void ConvertContentBlock_ResourceLinkBlock_WithMeta_ShouldPropagateToAddi
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- UriContent uriContent = result.Should().BeOfType().Subject;
- uriContent.AdditionalProperties.Should().NotBeNull();
- uriContent.AdditionalProperties!.Should().HaveCount(2);
- uriContent.AdditionalProperties["traceId"].Should().BeSameAs(block.Meta!["traceId"]);
- uriContent.AdditionalProperties["priority"].Should().BeSameAs(block.Meta["priority"]);
+ UriContent uriContent = Assert.IsType(result);
+ Assert.NotNull(uriContent.AdditionalProperties);
+ Assert.Equal(2, uriContent.AdditionalProperties.Count);
+ Assert.Same(block.Meta!["traceId"], uriContent.AdditionalProperties["traceId"]);
+ Assert.Same(block.Meta["priority"], uriContent.AdditionalProperties["priority"]);
}
[Fact]
@@ -841,9 +840,9 @@ public void ConvertContentBlock_ResourceLinkBlock_WithName_ShouldMapNameToFilena
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- UriContent uriContent = result.Should().BeOfType().Subject;
- uriContent.AdditionalProperties.Should().NotBeNull();
- uriContent.AdditionalProperties!["filename"].Should().Be("resource.bin");
+ UriContent uriContent = Assert.IsType(result);
+ Assert.NotNull(uriContent.AdditionalProperties);
+ Assert.Equal("resource.bin", uriContent.AdditionalProperties!["filename"]);
}
#pragma warning disable MCP9005 // Verify compatibility mapping for deprecated sampling content blocks.
@@ -863,12 +862,12 @@ public void ConvertContentBlock_ToolUseContentBlock_ShouldReturnFunctionCallCont
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- FunctionCallContent call = result.Should().BeOfType().Subject;
- call.CallId.Should().Be("call-1");
- call.Name.Should().Be("get_weather");
- call.Arguments.Should().NotBeNull();
- call.Arguments!.Should().ContainKey("city");
- call.RawRepresentation.Should().BeSameAs(block);
+ FunctionCallContent call = Assert.IsType(result);
+ Assert.Equal("call-1", call.CallId);
+ Assert.Equal("get_weather", call.Name);
+ Assert.NotNull(call.Arguments);
+ Assert.Contains("city", call.Arguments!);
+ Assert.Same(block, call.RawRepresentation);
}
[Fact]
@@ -886,10 +885,10 @@ public void ConvertContentBlock_ToolResultContentBlock_NotError_ShouldReturnFunc
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- FunctionResultContent functionResult = result.Should().BeOfType().Subject;
- functionResult.CallId.Should().Be("call-1");
- functionResult.Exception.Should().BeNull();
- functionResult.RawRepresentation.Should().BeSameAs(block);
+ FunctionResultContent functionResult = Assert.IsType(result);
+ Assert.Equal("call-1", functionResult.CallId);
+ Assert.Null(functionResult.Exception);
+ Assert.Same(block, functionResult.RawRepresentation);
}
[Fact]
@@ -907,10 +906,10 @@ public void ConvertContentBlock_ToolResultContentBlock_WithIsError_ShouldSetExce
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- FunctionResultContent functionResult = result.Should().BeOfType().Subject;
- functionResult.CallId.Should().Be("call-2");
- functionResult.Exception.Should().NotBeNull();
- functionResult.RawRepresentation.Should().BeSameAs(block);
+ FunctionResultContent functionResult = Assert.IsType(result);
+ Assert.Equal("call-2", functionResult.CallId);
+ Assert.NotNull(functionResult.Exception);
+ Assert.Same(block, functionResult.RawRepresentation);
}
#pragma warning restore MCP9005
@@ -932,9 +931,9 @@ public void ConvertContentBlock_BlockWithMeta_ShouldPropagateToAdditionalPropert
AIContent result = DefaultMcpToolHandler.ConvertContentBlock(block);
// Assert
- result.AdditionalProperties.Should().NotBeNull();
- result.AdditionalProperties!.Should().ContainKey("traceId");
- result.AdditionalProperties.Should().ContainKey("priority");
+ Assert.NotNull(result.AdditionalProperties);
+ Assert.True(result.AdditionalProperties!.ContainsKey("traceId"));
+ Assert.True(result.AdditionalProperties.ContainsKey("priority"));
}
#endregion
@@ -952,7 +951,7 @@ public void StripCredentialHeadersOnCrossOrigin_SameOrigin_RetainsAuthorization(
OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
// Assert — same origin, credential is preserved
- request.Headers.Contains("Authorization").Should().BeTrue();
+ Assert.True(request.Headers.Contains("Authorization"));
}
[Fact]
@@ -966,7 +965,7 @@ public void StripCredentialHeadersOnCrossOrigin_DifferentHost_RemovesAuthorizati
OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
// Assert — credential must not cross the origin boundary
- request.Headers.Contains("Authorization").Should().BeFalse();
+ Assert.False(request.Headers.Contains("Authorization"));
}
[Fact]
@@ -980,7 +979,7 @@ public void StripCredentialHeadersOnCrossOrigin_DifferentPort_RemovesAuthorizati
OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
// Assert
- request.Headers.Contains("Authorization").Should().BeFalse();
+ Assert.False(request.Headers.Contains("Authorization"));
}
[Fact]
@@ -995,7 +994,7 @@ public void StripCredentialHeadersOnCrossOrigin_ExplicitDefaultPort_RetainsAutho
OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com:443/mcp"));
// Assert — explicit vs implicit default port is the same origin
- request.Headers.Contains("Authorization").Should().BeTrue();
+ Assert.True(request.Headers.Contains("Authorization"));
}
[Fact]
@@ -1007,11 +1006,11 @@ public void StripCredentialHeadersOnCrossOrigin_RelativeRequestUri_RetainsAuthor
request.Headers.TryAddWithoutValidation("Authorization", "Bearer secret-token");
// Act
- Action act = () => OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
+ void act() => OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
// Assert — does not throw and leaves the credential in place
- act.Should().NotThrow();
- request.Headers.Contains("Authorization").Should().BeTrue();
+ Assert.Null(Record.Exception(act));
+ Assert.True(request.Headers.Contains("Authorization"));
}
[Fact]
@@ -1025,7 +1024,7 @@ public void StripCredentialHeadersOnCrossOrigin_DifferentScheme_RemovesAuthoriza
OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
// Assert
- request.Headers.Contains("Authorization").Should().BeFalse();
+ Assert.False(request.Headers.Contains("Authorization"));
}
[Fact]
@@ -1041,9 +1040,9 @@ public void StripCredentialHeadersOnCrossOrigin_CrossOrigin_RemovesCookieAndProx
OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
// Assert — all credential-bearing headers are stripped
- request.Headers.Contains("Authorization").Should().BeFalse();
- request.Headers.Contains("Cookie").Should().BeFalse();
- request.Headers.Contains("Proxy-Authorization").Should().BeFalse();
+ Assert.False(request.Headers.Contains("Authorization"));
+ Assert.False(request.Headers.Contains("Cookie"));
+ Assert.False(request.Headers.Contains("Proxy-Authorization"));
}
[Fact]
@@ -1058,8 +1057,8 @@ public void StripCredentialHeadersOnCrossOrigin_CrossOrigin_PreservesNonCredenti
OriginPinningHandler.StripCredentialHeadersOnCrossOrigin(request, new Uri("https://trusted.example.com"));
// Assert — only credential headers are removed; other headers are untouched
- request.Headers.Contains("Authorization").Should().BeFalse();
- request.Headers.Contains("X-Trace-Id").Should().BeTrue();
+ Assert.False(request.Headers.Contains("Authorization"));
+ Assert.True(request.Headers.Contains("X-Trace-Id"));
}
[Fact]
@@ -1077,8 +1076,8 @@ public async Task OriginPinningHandler_CrossOriginRequest_DoesNotForwardAuthoriz
using HttpResponseMessage response = await invoker.SendAsync(request, CancellationToken.None);
// Assert — the credential never reached the inner handler for the foreign origin
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- inner.LastRequestHadAuthorization.Should().BeFalse();
+ Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
+ Assert.False(inner.LastRequestHadAuthorization);
}
[Fact]
@@ -1096,8 +1095,8 @@ public async Task OriginPinningHandler_SameOriginRequest_ForwardsAuthorizationAs
using HttpResponseMessage response = await invoker.SendAsync(request, CancellationToken.None);
// Assert — same-origin credential flows through normally
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- inner.LastRequestHadAuthorization.Should().BeTrue();
+ Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
+ Assert.True(inner.LastRequestHadAuthorization);
}
private sealed class CapturingHandler : HttpMessageHandler
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests.csproj
index 057e2cd950c..51bcbf589bd 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests.csproj
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.Mcp.UnitTests.csproj
@@ -9,7 +9,6 @@
-
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DefaultHttpRequestHandlerTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DefaultHttpRequestHandlerTests.cs
index e679a89ca3d..6970bc336c2 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DefaultHttpRequestHandlerTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/DefaultHttpRequestHandlerTests.cs
@@ -7,7 +7,6 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests;
@@ -29,7 +28,7 @@ public async Task ConstructorWithNoParametersCreatesInstanceAsync()
await using DefaultHttpRequestHandler handler = new();
// Assert
- handler.Should().NotBeNull();
+ Assert.NotNull(handler);
}
[Fact]
@@ -39,17 +38,17 @@ public async Task ConstructorWithNullProviderCreatesInstanceAsync()
await using DefaultHttpRequestHandler handler = new(httpClientProvider: null);
// Assert
- handler.Should().NotBeNull();
+ Assert.NotNull(handler);
}
[Fact]
public void ConstructorWithNullHttpClientThrows()
{
// Act
- Action act = () => _ = new DefaultHttpRequestHandler((HttpClient)null!);
+ static void act() => _ = new DefaultHttpRequestHandler((HttpClient)null!);
// Assert
- act.Should().Throw();
+ Assert.Throws(act);
}
[Fact]
@@ -69,9 +68,9 @@ public async Task ConstructorWithHttpClientUsesSuppliedClientForAllRequestsAsync
HttpRequestResult result = await handler.SendAsync(request);
// Assert - the supplied HttpClient's underlying handler saw the request
- messageHandler.LastRequest.Should().NotBeNull();
- messageHandler.LastRequest!.RequestUri!.ToString().Should().Be(TestUrl);
- result.Body.Should().Be("ok");
+ Assert.NotNull(messageHandler.LastRequest);
+ Assert.Equal(TestUrl, messageHandler.LastRequest!.RequestUri!.ToString());
+ Assert.Equal("ok", result.Body);
}
[Fact]
@@ -87,8 +86,8 @@ public async Task DisposeAsyncDoesNotDisposeCallerSuppliedHttpClientAsync()
await handler.DisposeAsync();
// Assert - supplied client remains usable (not disposed)
- Func act = async () => await suppliedClient.GetAsync(new Uri(TestUrl));
- await act.Should().NotThrowAsync();
+ async Task actAsync() => await suppliedClient.GetAsync(new Uri(TestUrl));
+ Assert.IsNotType(await Record.ExceptionAsync(actAsync));
}
#endregion
@@ -102,10 +101,10 @@ public async Task SendAsyncWithNullRequestThrowsAsync()
await using DefaultHttpRequestHandler handler = new();
// Act
- Func act = async () => await handler.SendAsync(null!);
+ async Task actAsync() => await handler.SendAsync(null!);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -116,10 +115,10 @@ public async Task SendAsyncWithEmptyUrlThrowsAsync()
HttpRequestInfo request = new() { Method = "GET", Url = "" };
// Act
- Func act = async () => await handler.SendAsync(request);
+ async Task actAsync() => await handler.SendAsync(request);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
[Fact]
@@ -130,10 +129,10 @@ public async Task SendAsyncWithEmptyMethodThrowsAsync()
HttpRequestInfo request = new() { Method = "", Url = TestUrl };
// Act
- Func act = async () => await handler.SendAsync(request);
+ async Task actAsync() => await handler.SendAsync(request);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
#endregion
@@ -158,12 +157,12 @@ public async Task SendAsyncUsesProvidedHttpClientAsync()
HttpRequestResult result = await handler.SendAsync(request);
// Assert
- messageHandler.LastRequest.Should().NotBeNull();
- messageHandler.LastRequest!.Method.Should().Be(HttpMethod.Get);
- messageHandler.LastRequest.RequestUri!.ToString().Should().Be(TestUrl);
- result.StatusCode.Should().Be(200);
- result.IsSuccessStatusCode.Should().BeTrue();
- result.Body.Should().Be("hello");
+ Assert.NotNull(messageHandler.LastRequest);
+ Assert.Equal(HttpMethod.Get, messageHandler.LastRequest!.Method);
+ Assert.Equal(TestUrl, messageHandler.LastRequest.RequestUri!.ToString());
+ Assert.Equal(200, result.StatusCode);
+ Assert.True(result.IsSuccessStatusCode);
+ Assert.Equal("hello", result.Body);
}
[Fact]
@@ -183,7 +182,7 @@ public async Task SendAsyncMapsAllKnownMethodsAsync()
await handler.SendAsync(request);
// Assert
- messageHandler.LastRequest!.Method.Method.Should().Be(method);
+ Assert.Equal(method, messageHandler.LastRequest!.Method.Method);
}
}
@@ -200,7 +199,7 @@ public async Task SendAsyncNormalizesWhitespaceAroundCustomMethodAsync()
await handler.SendAsync(request);
// Assert - fallback path should apply the same Trim/ToUpperInvariant normalization.
- messageHandler.LastRequest!.Method.Method.Should().Be("CUSTOM");
+ Assert.Equal("CUSTOM", messageHandler.LastRequest!.Method.Method);
}
[Fact]
@@ -224,8 +223,8 @@ public async Task SendAsyncAppliesBodyAndContentTypeAsync()
await handler.SendAsync(request);
// Assert
- messageHandler.LastRequestBody.Should().Be("{\"hello\":\"world\"}");
- messageHandler.LastRequestContentType.Should().Be("application/json");
+ Assert.Equal("{\"hello\":\"world\"}", messageHandler.LastRequestBody);
+ Assert.Equal("application/json", messageHandler.LastRequestContentType);
}
[Fact]
@@ -252,8 +251,8 @@ public async Task SendAsyncAppliesRequestHeadersAsync()
await handler.SendAsync(request);
// Assert
- messageHandler.LastRequest!.Headers.Authorization!.ToString().Should().Be("Bearer secret");
- messageHandler.LastRequest.Headers.Accept.Should().Contain(mediaType => mediaType.MediaType == "application/json");
+ Assert.Equal("Bearer secret", messageHandler.LastRequest!.Headers.Authorization!.ToString());
+ Assert.Contains(messageHandler.LastRequest.Headers.Accept, mediaType => mediaType.MediaType == "application/json");
}
[Fact]
@@ -281,7 +280,7 @@ public async Task SendAsyncRoutesContentHeadersToBodyAsync()
await handler.SendAsync(request);
// Assert
- messageHandler.LastRequest!.Content!.Headers.ContentLanguage.Should().Contain("en-US");
+ Assert.Contains("en-US", messageHandler.LastRequest!.Content!.Headers.ContentLanguage);
}
[Fact]
@@ -309,11 +308,11 @@ public async Task SendAsyncCapturesResponseHeadersAsync()
HttpRequestResult result = await handler.SendAsync(request);
// Assert
- result.Headers.Should().NotBeNull();
- result.Headers!.Should().ContainKey("X-Request-Id");
- result.Headers!["Set-Cookie"].Should().BeEquivalentTo(s_setCookieValues);
+ Assert.NotNull(result.Headers);
+ Assert.Contains("X-Request-Id", result.Headers!);
+ Assert.Equivalent(s_setCookieValues, result.Headers!["Set-Cookie"]);
// Content headers also flattened in.
- result.Headers!.Should().ContainKey("Content-Type");
+ Assert.Contains("Content-Type", result.Headers!);
}
[Fact]
@@ -334,9 +333,9 @@ public async Task SendAsyncReturnsFailureStatusWithoutThrowingAsync()
HttpRequestResult result = await handler.SendAsync(request);
// Assert
- result.IsSuccessStatusCode.Should().BeFalse();
- result.StatusCode.Should().Be(400);
- result.Body.Should().Be("bad request");
+ Assert.False(result.IsSuccessStatusCode);
+ Assert.Equal(400, result.StatusCode);
+ Assert.Equal("bad request", result.Body);
}
[Fact]
@@ -359,10 +358,10 @@ public async Task SendAsyncTimeoutCancelsRequestAsync()
};
// Act
- Func act = async () => await handler.SendAsync(request);
+ async Task actAsync() => await handler.SendAsync(request);
// Assert
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAnyAsync(actAsync);
}
[Fact]
@@ -379,11 +378,11 @@ public async Task SendAsyncFallsBackToOwnedClientWhenProviderReturnsNullAsync()
HttpRequestInfo request = new() { Method = "GET", Url = "http://127.0.0.1:1/" };
// Act - owned client will attempt real network and fail, but provider path should have been consulted first.
- Func act = async () => await handler.SendAsync(request);
+ async Task actAsync() => await handler.SendAsync(request);
// Assert
- await act.Should().ThrowAsync();
- providerCallCount.Should().Be(1);
+ await Assert.ThrowsAnyAsync(actAsync);
+ Assert.Equal(1, providerCallCount);
}
#endregion
@@ -397,10 +396,10 @@ public async Task DisposeAsyncCompletesAsync()
DefaultHttpRequestHandler handler = new();
// Act
- Func act = async () => await handler.DisposeAsync();
+ async Task actAsync() => await handler.DisposeAsync();
// Assert
- await act.Should().NotThrowAsync();
+ Assert.Null(await Record.ExceptionAsync(actAsync));
}
[Fact]
@@ -411,10 +410,10 @@ public async Task DisposeAsyncCalledMultipleTimesSucceedsAsync()
// Act
await handler.DisposeAsync();
- Func second = async () => await handler.DisposeAsync();
+ async Task secondAsync() => await handler.DisposeAsync();
// Assert
- await second.Should().NotThrowAsync();
+ Assert.Null(await Record.ExceptionAsync(secondAsync));
}
#endregion
@@ -444,10 +443,10 @@ public async Task QueryParametersAreAppendedToUrlAsync()
await handler.SendAsync(info);
// Assert
- fake.LastRequest.Should().NotBeNull();
+ Assert.NotNull(fake.LastRequest);
string? query = fake.LastRequest!.RequestUri!.Query;
- query.Should().Contain("filter=active%20items");
- query.Should().Contain("ids=1%2C2%2C3");
+ Assert.Contains("filter=active%20items", query);
+ Assert.Contains("ids=1%2C2%2C3", query);
}
[Fact]
@@ -472,7 +471,7 @@ public async Task QueryParametersPreserveExistingQueryStringAsync()
await handler.SendAsync(info);
// Assert
- fake.LastRequest!.RequestUri!.Query.Should().Be("?existing=yes&added=true");
+ Assert.Equal("?existing=yes&added=true", fake.LastRequest!.RequestUri!.Query);
}
#endregion
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Kit/PortableValuePredicateTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Kit/PortableValuePredicateTests.cs
index 4ed50afb5ad..d63fa49f9e6 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Kit/PortableValuePredicateTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Kit/PortableValuePredicateTests.cs
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft. All rights reserved.
-using FluentAssertions;
using Microsoft.Agents.AI.Workflows.Declarative.Events;
using Microsoft.Agents.AI.Workflows.Declarative.Kit;
using Microsoft.Agents.AI.Workflows.Declarative.ObjectModel;
@@ -25,7 +24,7 @@ public void ActionExecutorResult_ThrowIfNot_WithDirectActionExecutorResult_Retur
ActionExecutorResult actual = ActionExecutorResult.ThrowIfNot(result);
// Assert
- actual.Should().BeSameAs(result);
+ Assert.Same(result, actual);
}
[Fact]
@@ -39,7 +38,7 @@ public void ActionExecutorResult_ThrowIfNot_WithPortableValueWrappedActionExecut
ActionExecutorResult actual = ActionExecutorResult.ThrowIfNot(wrapped);
// Assert
- actual.ExecutorId.Should().Be("test-executor");
+ Assert.Equal("test-executor", actual.ExecutorId);
}
[Fact]
@@ -80,7 +79,7 @@ public void InvokeAzureAgentExecutor_RequiresInput_WithDirectExternalInputReques
ExternalInputRequest request = new("test prompt");
// Act & Assert
- InvokeAzureAgentExecutor.RequiresInput(request).Should().BeTrue();
+ Assert.True(InvokeAzureAgentExecutor.RequiresInput(request));
}
[Fact]
@@ -91,7 +90,7 @@ public void InvokeAzureAgentExecutor_RequiresInput_WithPortableValueWrappedReque
PortableValue wrapped = new(request);
// Act & Assert
- InvokeAzureAgentExecutor.RequiresInput(wrapped).Should().BeTrue();
+ Assert.True(InvokeAzureAgentExecutor.RequiresInput(wrapped));
}
[Fact]
@@ -101,7 +100,7 @@ public void InvokeAzureAgentExecutor_RequiresInput_WithActionExecutorResult_Retu
ActionExecutorResult result = new("test");
// Act & Assert
- InvokeAzureAgentExecutor.RequiresInput(result).Should().BeFalse();
+ Assert.False(InvokeAzureAgentExecutor.RequiresInput(result));
}
[Fact]
@@ -111,7 +110,7 @@ public void InvokeAzureAgentExecutor_RequiresNothing_WithDirectActionExecutorRes
ActionExecutorResult result = new("test");
// Act & Assert
- InvokeAzureAgentExecutor.RequiresNothing(result).Should().BeTrue();
+ Assert.True(InvokeAzureAgentExecutor.RequiresNothing(result));
}
[Fact]
@@ -122,7 +121,7 @@ public void InvokeAzureAgentExecutor_RequiresNothing_WithPortableValueWrappedRes
PortableValue wrapped = new(result);
// Act & Assert
- InvokeAzureAgentExecutor.RequiresNothing(wrapped).Should().BeTrue();
+ Assert.True(InvokeAzureAgentExecutor.RequiresNothing(wrapped));
}
[Fact]
@@ -132,7 +131,7 @@ public void InvokeAzureAgentExecutor_RequiresNothing_WithExternalInputRequest_Re
ExternalInputRequest request = new("test prompt");
// Act & Assert
- InvokeAzureAgentExecutor.RequiresNothing(request).Should().BeFalse();
+ Assert.False(InvokeAzureAgentExecutor.RequiresNothing(request));
}
#endregion
@@ -147,7 +146,7 @@ public void InvokeMcpToolExecutor_RequiresInput_WithPortableValueWrappedRequest_
PortableValue wrapped = new(request);
// Act & Assert
- InvokeMcpToolExecutor.RequiresInput(wrapped).Should().BeTrue();
+ Assert.True(InvokeMcpToolExecutor.RequiresInput(wrapped));
}
[Fact]
@@ -158,7 +157,7 @@ public void InvokeMcpToolExecutor_RequiresNothing_WithPortableValueWrappedResult
PortableValue wrapped = new(result);
// Act & Assert
- InvokeMcpToolExecutor.RequiresNothing(wrapped).Should().BeTrue();
+ Assert.True(InvokeMcpToolExecutor.RequiresNothing(wrapped));
}
#endregion
@@ -173,7 +172,7 @@ public void QuestionExecutor_IsComplete_WithPortableValueWrappedResult_NullResul
PortableValue wrapped = new(result);
// Act & Assert
- QuestionExecutor.IsComplete(wrapped).Should().BeTrue();
+ Assert.True(QuestionExecutor.IsComplete(wrapped));
}
[Fact]
@@ -184,7 +183,7 @@ public void QuestionExecutor_IsComplete_WithPortableValueWrappedResult_NonNullRe
PortableValue wrapped = new(result);
// Act & Assert
- QuestionExecutor.IsComplete(wrapped).Should().BeFalse();
+ Assert.False(QuestionExecutor.IsComplete(wrapped));
}
#endregion
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests.csproj
index 57d4858dbbe..470a7fca49b 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests.csproj
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests.csproj
@@ -12,7 +12,6 @@
-
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/ExecutorRouteGeneratorTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/ExecutorRouteGeneratorTests.cs
index 15fb2429c67..d9522872601 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/ExecutorRouteGeneratorTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/ExecutorRouteGeneratorTests.cs
@@ -2,7 +2,6 @@
using System;
using System.Linq;
-using FluentAssertions;
namespace Microsoft.Agents.AI.Workflows.Generators.UnitTests;
@@ -36,11 +35,11 @@ private void HandleMessage(string message, IWorkflowContext context)
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().AddHandler("this.HandleMessage", "string");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleMessage", "string");
}
[Fact]
@@ -67,10 +66,10 @@ private ValueTask HandleMessageAsync(string message, IWorkflowContext context)
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0].ToString();
- generated.Should().Contain(".AddHandler(this.HandleMessageAsync)");
+ Assert.Contains(".AddHandler(this.HandleMessageAsync)", generated);
}
[Fact]
@@ -97,10 +96,10 @@ private ValueTask HandleMessageAsync(string message, IWorkflowContext conte
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0].ToString();
- generated.Should().Contain(".AddHandler(this.HandleMessageAsync)");
+ Assert.Contains(".AddHandler(this.HandleMessageAsync)", generated);
}
[Fact]
@@ -127,10 +126,10 @@ private ValueTask HandleMessageAsync(string message, IWorkflowContext context, C
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0].ToString();
- generated.Should().Contain(".AddHandler(this.HandleMessageAsync)");
+ Assert.Contains(".AddHandler(this.HandleMessageAsync)", generated);
}
#endregion
@@ -167,12 +166,12 @@ private ValueTask HandleDoubleAsync(double message, IWorkflowContext con
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0].ToString();
- generated.Should().Contain(".AddHandler(this.HandleString)");
- generated.Should().Contain(".AddHandler(this.HandleInt)");
- generated.Should().Contain(".AddHandler(this.HandleDoubleAsync)");
+ Assert.Contains(".AddHandler(this.HandleString)", generated);
+ Assert.Contains(".AddHandler(this.HandleInt)", generated);
+ Assert.Contains(".AddHandler(this.HandleDoubleAsync)", generated);
}
#endregion
@@ -203,11 +202,11 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().RegisterYieldedOutputType("global::TestNamespace.OutputMessage");
+ SyntaxTreeAssert.RegisterYieldedOutputType(generated, "global::TestNamespace.OutputMessage");
}
[Fact]
@@ -234,10 +233,10 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().RegisterSentMessageType("global::TestNamespace.SendMessage");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "global::TestNamespace.SendMessage");
}
[Fact]
@@ -265,10 +264,10 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().RegisterSentMessageType("global::TestNamespace.BroadcastMessage");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "global::TestNamespace.BroadcastMessage");
}
[Fact]
@@ -296,10 +295,10 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().RegisterYieldedOutputType("global::TestNamespace.YieldedMessage");
+ SyntaxTreeAssert.RegisterYieldedOutputType(generated, "global::TestNamespace.YieldedMessage");
}
#endregion
@@ -330,13 +329,13 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().HaveHierarchy("OuterClass", "TestExecutor")
- .And.AddHandler("this.HandleMessage", "string");
+ SyntaxTreeAssert.HaveHierarchy(generated, "OuterClass", "TestExecutor");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleMessage", "string");
}
[Fact]
@@ -366,13 +365,13 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().HaveHierarchy("Outer", "Inner", "TestExecutor")
- .And.AddHandler("this.HandleMessage", "string");
+ SyntaxTreeAssert.HaveHierarchy(generated, "Outer", "Inner", "TestExecutor");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleMessage", "string");
}
[Fact]
@@ -405,13 +404,13 @@ private void HandleMessage(int message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().HaveHierarchy("Level1", "Level2", "Level3", "TestExecutor")
- .And.AddHandler("this.HandleMessage", "int");
+ SyntaxTreeAssert.HaveHierarchy(generated, "Level1", "Level2", "Level3", "TestExecutor");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleMessage", "int");
}
[Fact]
@@ -436,14 +435,14 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().NotHaveNamespace()
- .And.HaveHierarchy("OuterClass", "TestExecutor")
- .And.AddHandler("this.HandleMessage", "string");
+ SyntaxTreeAssert.NotHaveNamespace(generated);
+ SyntaxTreeAssert.HaveHierarchy(generated, "OuterClass", "TestExecutor");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleMessage", "string");
}
[Fact]
@@ -479,15 +478,14 @@ private ValueTask HandleMessage(int message, IWorkflowContext context)
var result = GeneratorTestHelper.RunGenerator(source);
// No generator diagnostics
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Empty(result.RunResult.Diagnostics);
// Check that the combined compilation (source + generated) has no errors
var compilationDiagnostics = result.OutputCompilation.GetDiagnostics()
.Where(d => d.Severity == CodeAnalysis.DiagnosticSeverity.Error)
.ToList();
- compilationDiagnostics.Should().BeEmpty(
- "generated code for nested classes should compile without errors");
+ Assert.Empty(compilationDiagnostics ?? []);
}
[Fact]
@@ -517,7 +515,7 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0].ToString();
@@ -525,7 +523,7 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var openBraces = generated.Count(c => c == '{');
var closeBraces = generated.Count(c => c == '}');
- openBraces.Should().Be(closeBraces, "generated code should have balanced braces");
+ Assert.Equal(closeBraces, openBraces);
// For Outer.Inner.TestExecutor, we expect:
// - 1 for Outer class
@@ -533,7 +531,7 @@ private void HandleMessage(string message, IWorkflowContext context) { }
// - 1 for TestExecutor class
// - 1 for ConfigureProtocol method
// = 4 pairs minimum
- openBraces.Should().BeGreaterThanOrEqualTo(4, "should have braces for all nested classes and method");
+ Assert.True(openBraces >= 4);
}
#endregion
@@ -585,22 +583,21 @@ private ValueTask HandleIntAsync(int message, IWorkflowContext context)
var result = GeneratorTestHelper.RunGenerator(file1, file2);
// Should generate one file for the executor
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
// Should have both handlers registered
- generated.Should().AddHandler("this.HandleString", "string")
- .And.AddHandler("this.HandleIntAsync", "int");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleString", "string");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleIntAsync", "int");
// Verify the generated code compiles with all three partials combined
var compilationErrors = result.OutputCompilation.GetDiagnostics()
.Where(d => d.Severity == CodeAnalysis.DiagnosticSeverity.Error)
.ToList();
- compilationErrors.Should().BeEmpty(
- "generated partial should compile correctly with the other partial files");
+ Assert.Empty(compilationErrors ?? []);
}
[Fact]
@@ -640,14 +637,14 @@ private void HandleFromFile2(int message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(file1, file2);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
// Both handlers from different files should be registered
- generated.Should().AddHandler("this.HandleFromFile1", "string")
- .And.AddHandler("this.HandleFromFile2", "int");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleFromFile1", "string");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleFromFile2", "int");
}
[Fact]
@@ -691,16 +688,16 @@ private void HandleFromFile2(int message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(file1, file2);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
// Verify SendsMessage and YieldsOutput from both partials are combined correctly
- generated.Should().RegisterSentMessageType("string")
- .And.RegisterSentMessageType("int")
- .And.RegisterYieldedOutputType("string")
- .And.RegisterYieldedOutputType("int");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "string");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "int");
+ SyntaxTreeAssert.RegisterYieldedOutputType(generated, "string");
+ SyntaxTreeAssert.RegisterYieldedOutputType(generated, "int");
}
#endregion
@@ -729,11 +726,10 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
// Should produce MAFGENWF003 diagnostic
- result.RunResult.Diagnostics.Should().Contain(d => d.Id == "MAFGENWF003");
+ Assert.Contains(result.RunResult.Diagnostics, d => d.Id == "MAFGENWF003");
// Should NOT generate any source (to avoid CS0260)
- result.RunResult.GeneratedTrees.Should().BeEmpty(
- "non-partial classes should not have source generated to avoid CS0260 compiler error");
+ Assert.Empty(result.RunResult.GeneratedTrees);
}
[Fact]
@@ -755,7 +751,7 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.Diagnostics.Should().Contain(d => d.Id == "MAFGENWF004");
+ Assert.Contains(result.RunResult.Diagnostics, d => d.Id == "MAFGENWF004");
}
[Fact]
@@ -779,7 +775,7 @@ private static void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.Diagnostics.Should().Contain(d => d.Id == "MAFGENWF007");
+ Assert.Contains(result.RunResult.Diagnostics, d => d.Id == "MAFGENWF007");
}
[Fact]
@@ -803,7 +799,7 @@ private void HandleMessage(string message) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.Diagnostics.Should().Contain(d => d.Id == "MAFGENWF005");
+ Assert.Contains(result.RunResult.Diagnostics, d => d.Id == "MAFGENWF005");
}
[Fact]
@@ -827,7 +823,7 @@ private void HandleMessage(string message, string notContext) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.Diagnostics.Should().Contain(d => d.Id == "MAFGENWF001");
+ Assert.Contains(result.RunResult.Diagnostics, d => d.Id == "MAFGENWF001");
}
#endregion
@@ -861,8 +857,8 @@ private void HandleMessage(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
// Should produce diagnostic but not generate code
- result.RunResult.Diagnostics.Should().Contain(d => d.Id == "MAFGENWF006");
- result.RunResult.GeneratedTrees.Should().BeEmpty();
+ Assert.Contains(result.RunResult.Diagnostics, d => d.Id == "MAFGENWF006");
+ Assert.Empty(result.RunResult.GeneratedTrees);
}
[Fact]
@@ -885,7 +881,7 @@ private void SomeOtherMethod(string message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().BeEmpty();
+ Assert.Empty(result.RunResult.GeneratedTrees);
}
#endregion
@@ -918,13 +914,13 @@ public TestExecutor() : base("test") { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().RegisterSentMessageType("global::TestNamespace.MessageA")
- .And.RegisterSentMessageType("global::TestNamespace.MessageB")
- .And.RegisterSentMessageType("global::TestNamespace.MessageC");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "global::TestNamespace.MessageA");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "global::TestNamespace.MessageB");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "global::TestNamespace.MessageC");
}
[Theory]
@@ -951,12 +947,11 @@ public TestExecutor() : base("test") { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.Diagnostics.Should().ContainSingle();
+ Assert.Single(result.RunResult.Diagnostics);
var diagnostic = result.RunResult.Diagnostics.Single();
- diagnostic.Id.Should().Be("MAFGENWF008");
- diagnostic.GetMessage().Should().Be(
- "Class 'TestExecutor' uses [SendsMessage] or [YieldsOutput] but is not declared as partial");
- result.RunResult.GeneratedTrees.Should().BeEmpty();
+ Assert.Equal("MAFGENWF008", diagnostic.Id);
+ Assert.Equal("Class 'TestExecutor' uses [SendsMessage] or [YieldsOutput] but is not declared as partial", diagnostic.GetMessage());
+ Assert.Empty(result.RunResult.GeneratedTrees);
}
[Fact]
@@ -988,12 +983,11 @@ internal sealed record ReduceComplete(string FilePath);
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.Diagnostics.Should().ContainSingle();
+ Assert.Single(result.RunResult.Diagnostics);
var diagnostic = result.RunResult.Diagnostics.Single();
- diagnostic.Id.Should().Be("MAFGENWF008");
- diagnostic.GetMessage().Should().Be(
- "Class 'CompletionExecutor' uses [SendsMessage] or [YieldsOutput] but is not declared as partial");
- result.RunResult.GeneratedTrees.Should().BeEmpty();
+ Assert.Equal("MAFGENWF008", diagnostic.Id);
+ Assert.Equal("Class 'CompletionExecutor' uses [SendsMessage] or [YieldsOutput] but is not declared as partial", diagnostic.GetMessage());
+ Assert.Empty(result.RunResult.GeneratedTrees);
}
[Theory]
@@ -1019,12 +1013,11 @@ public partial class NotAnExecutor
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.Diagnostics.Should().ContainSingle();
+ Assert.Single(result.RunResult.Diagnostics);
var diagnostic = result.RunResult.Diagnostics.Single();
- diagnostic.Id.Should().Be("MAFGENWF009");
- diagnostic.GetMessage().Should().Be(
- "Class 'NotAnExecutor' uses [SendsMessage] or [YieldsOutput] but does not derive from Executor");
- result.RunResult.GeneratedTrees.Should().BeEmpty();
+ Assert.Equal("MAFGENWF009", diagnostic.Id);
+ Assert.Equal("Class 'NotAnExecutor' uses [SendsMessage] or [YieldsOutput] but does not derive from Executor", diagnostic.GetMessage());
+ Assert.Empty(result.RunResult.GeneratedTrees);
}
[Fact]
@@ -1052,15 +1045,15 @@ public TestExecutor() : base("test") { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0];
// Verify partial declarations are present
- generated.Should().HaveHierarchy("OuterClass", "TestExecutor")
+ SyntaxTreeAssert.HaveHierarchy(generated, "OuterClass", "TestExecutor");
// Verify protocol types are generated
- .And.RegisterSentMessageType("global::TestNamespace.BroadcastMessage");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "global::TestNamespace.BroadcastMessage");
}
[Fact]
@@ -1085,12 +1078,12 @@ public GenericExecutor() : base("generic") { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().HaveHierarchy("GenericExecutor")
- .And.RegisterSentMessageType("global::TestNamespace.BroadcastMessage");
+ SyntaxTreeAssert.HaveHierarchy(generated, "GenericExecutor");
+ SyntaxTreeAssert.RegisterSentMessageType(generated, "global::TestNamespace.BroadcastMessage");
}
[Fact]
@@ -1123,17 +1116,16 @@ public override System.Threading.Tasks.ValueTask HandleAsync(string message, IWo
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0].ToString();
// Base class Executor overrides ConfigureProtocol, so the generated override
// must chain to base to preserve the inherited handler registration.
- generated.Should().Contain("return base.ConfigureProtocol(protocolBuilder)",
- because: "Executor overrides ConfigureProtocol, so base must be called to preserve its handler registration");
- generated.Should().Contain(".SendsMessage()");
- generated.Should().Contain(".YieldsOutput()");
+ Assert.Contains("return base.ConfigureProtocol(protocolBuilder)", generated);
+ Assert.Contains(".SendsMessage()", generated);
+ Assert.Contains(".YieldsOutput()", generated);
}
[Fact]
@@ -1161,15 +1153,14 @@ public BroadcastExecutor() : base("broadcast") { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
- result.RunResult.Diagnostics.Should().BeEmpty();
+ Assert.Single(result.RunResult.GeneratedTrees);
+ Assert.Empty(result.RunResult.Diagnostics);
var generated = result.RunResult.GeneratedTrees[0].ToString();
// Executor's ConfigureProtocol is abstract — no base call needed.
- generated.Should().Contain("return protocolBuilder",
- because: "Executor base class has no non-abstract ConfigureProtocol, so no base call is needed");
- generated.Should().NotContain("base.ConfigureProtocol");
+ Assert.Contains("return protocolBuilder", generated);
+ Assert.DoesNotContain("base.ConfigureProtocol", generated);
}
#endregion
@@ -1197,12 +1188,12 @@ private void HandleMessage(T message, IWorkflowContext context) { }
var result = GeneratorTestHelper.RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1);
+ Assert.Single(result.RunResult.GeneratedTrees);
var generated = result.RunResult.GeneratedTrees[0];
- generated.Should().HaveHierarchy("GenericExecutor")
- .And.AddHandler("this.HandleMessage", "T");
+ SyntaxTreeAssert.HaveHierarchy(generated, "GenericExecutor");
+ SyntaxTreeAssert.AddHandler(generated, "this.HandleMessage", "T");
}
#endregion
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/GeneratorTestHelper.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/GeneratorTestHelper.cs
index f631fc85515..a063c332ded 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/GeneratorTestHelper.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/GeneratorTestHelper.cs
@@ -8,7 +8,6 @@
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -60,10 +59,10 @@ public static void AssertGeneratesSource(string source, string expectedGenerated
{
var result = RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().HaveCount(1, "expected exactly one generated file");
+ Assert.Single(result.RunResult.GeneratedTrees);
var generatedSource = result.RunResult.GeneratedTrees[0].ToString();
- generatedSource.Should().Contain(expectedGeneratedSource);
+ Assert.Contains(expectedGeneratedSource, generatedSource);
}
///
@@ -72,7 +71,7 @@ public static void AssertGeneratesSource(string source, string expectedGenerated
public static void AssertGeneratesNoSource(string source)
{
var result = RunGenerator(source);
- result.RunResult.GeneratedTrees.Should().BeEmpty("expected no generated files");
+ Assert.Empty(result.RunResult.GeneratedTrees);
}
///
@@ -83,8 +82,7 @@ public static void AssertProducesDiagnostic(string source, string diagnosticId)
var result = RunGenerator(source);
var generatorDiagnostics = result.RunResult.Diagnostics;
- generatorDiagnostics.Should().Contain(d => d.Id == diagnosticId,
- $"expected diagnostic {diagnosticId} to be produced");
+ Assert.Contains(generatorDiagnostics, d => d.Id == diagnosticId);
}
///
@@ -98,7 +96,7 @@ public static void AssertCompilationSucceeds(string source)
.Where(d => d.Severity == DiagnosticSeverity.Error)
.ToList();
- errors.Should().BeEmpty("compilation should succeed without errors");
+ Assert.Empty(errors ?? []);
}
private static ImmutableArray GetMetadataReferences()
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/Microsoft.Agents.AI.Workflows.Generators.UnitTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/Microsoft.Agents.AI.Workflows.Generators.UnitTests.csproj
index 81b91bf17d3..4720e85695d 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/Microsoft.Agents.AI.Workflows.Generators.UnitTests.csproj
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/Microsoft.Agents.AI.Workflows.Generators.UnitTests.csproj
@@ -16,7 +16,6 @@
-
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/SyntaxTreeFluentExtensions.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/SyntaxTreeFluentExtensions.cs
index 3da1e7d8911..d564a7eb485 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/SyntaxTreeFluentExtensions.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Generators.UnitTests/SyntaxTreeFluentExtensions.cs
@@ -1,220 +1,137 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
-using FluentAssertions;
-using FluentAssertions.Execution;
-using FluentAssertions.Primitives;
using Microsoft.CodeAnalysis;
namespace Microsoft.Agents.AI.Workflows.Generators.UnitTests;
-internal sealed class SyntaxTreeAssertions : ObjectAssertions
+internal static class SyntaxTreeAssert
{
- private readonly string _syntaxString;
-
- public SyntaxTreeAssertions(SyntaxTree instance, AssertionChain assertionChain) : base(instance, assertionChain)
- {
- this._syntaxString = instance.ToString();
- }
-
- public AndConstraint AddHandler(string handlerName)
+ public static void AddHandler(SyntaxTree syntaxTree, string handlerName)
{
+ string syntaxString = syntaxTree.ToString();
string expectedRegistration = $".AddHandler({handlerName})";
- this.CurrentAssertionChain
- .ForCondition(this._syntaxString.Contains(expectedRegistration))
- .BecauseOf($"expected handler {handlerName} to be registered")
- .FailWith("Expected {context} to contain handler registration {0}{reason}, but it was not found. Actual syntax: {1}",
- expectedRegistration, this._syntaxString);
-
- return new(this);
+ Assert.Contains(expectedRegistration, syntaxString);
}
- public AndConstraint AddHandler(string handlerName, string inTypeParam)
+ public static void AddHandler(SyntaxTree syntaxTree, string handlerName, string inTypeParam)
{
+ string syntaxString = syntaxTree.ToString();
string expectedRegistration = $".AddHandler<{inTypeParam}>({handlerName})";
- this.CurrentAssertionChain
- .ForCondition(this._syntaxString.Contains(expectedRegistration))
- .BecauseOf($"expected handler {handlerName} to be registered")
- .FailWith("Expected {context} to contain handler registration {0}{reason}, but it was not found. Actual syntax: {1}",
- expectedRegistration, this._syntaxString);
-
- return new(this);
+ Assert.Contains(expectedRegistration, syntaxString);
}
- public AndConstraint AddHandler(string handlerName, string inTypeParam, string outTypeParam)
+ public static void AddHandler(SyntaxTree syntaxTree, string handlerName, string inTypeParam, string outTypeParam)
{
+ string syntaxString = syntaxTree.ToString();
string expectedRegistration = $".AddHandler<{inTypeParam},{outTypeParam}>({handlerName})";
- this.CurrentAssertionChain
- .ForCondition(this._syntaxString.Contains(expectedRegistration))
- .BecauseOf($"expected handler {handlerName} to be registered")
- .FailWith("Expected {context} to contain handler registration {0}{reason}, but it was not found. Actual syntax: {1}",
- expectedRegistration, this._syntaxString);
-
- return new(this);
+ Assert.Contains(expectedRegistration, syntaxString);
}
- public AndConstraint AddHandler(string handlerName, bool globalQualified = false)
+ public static void AddHandler(SyntaxTree syntaxTree, string handlerName, bool globalQualified = false)
{
Type inType = typeof(TIn);
string inTypeParam = globalQualified ? $"global::{inType.FullName}" : inType.Name;
- return this.AddHandler(handlerName, inTypeParam);
+ AddHandler(syntaxTree, handlerName, inTypeParam);
}
- public AndConstraint AddHandler(string handlerName, bool globalQualified = false)
+ public static void AddHandler(SyntaxTree syntaxTree, string handlerName, bool globalQualified = false)
{
Type inType = typeof(TIn), outType = typeof(TOut);
string inTypeParam = globalQualified ? $"global::{inType.FullName}" : inType.Name;
string outTypeParam = globalQualified ? $"global::{outType.FullName}" : outType.Name;
- return this.AddHandler(handlerName, inTypeParam, outTypeParam);
+ AddHandler(syntaxTree, handlerName, inTypeParam, outTypeParam);
}
- public AndConstraint HaveNoHandlers()
+ public static void HaveNoHandlers(SyntaxTree syntaxTree)
{
- this.CurrentAssertionChain
- .ForCondition(!this._syntaxString.Contains(".AddHandler("))
- .BecauseOf("expected no handlers to be registered")
- .FailWith("Expected {context} to have no handler registrations{reason}, but found at least one. Actual syntax: {1}",
- this._syntaxString);
-
- return new(this);
+ Assert.DoesNotContain(".AddHandler(", syntaxTree.ToString());
}
- public AndConstraint RegisterSentMessageType(string messageTypeParam)
+ public static void RegisterSentMessageType(SyntaxTree syntaxTree, string messageTypeParam)
{
+ string syntaxString = syntaxTree.ToString();
string expectedRegistration = $".SendsMessage<{messageTypeParam}>()";
- this.CurrentAssertionChain
- .ForCondition(this._syntaxString.Contains(expectedRegistration))
- .BecauseOf($"expected message type {messageTypeParam} to be registered")
- .FailWith("Expected {context} to contain message type registration {0}{reason}, but it was not found. Actual syntax: {1}",
- expectedRegistration, this._syntaxString);
-
- return new(this);
+ Assert.Contains(expectedRegistration, syntaxString);
}
- public AndConstraint RegisterSentMessageType(bool globalQualified = true)
+ public static void RegisterSentMessageType(SyntaxTree syntaxTree, bool globalQualified = true)
{
Type messageType = typeof(TMessage);
string messageTypeParam = globalQualified ? $"global::{messageType.FullName}" : messageType.Name;
- return this.RegisterSentMessageType(messageTypeParam);
+ RegisterSentMessageType(syntaxTree, messageTypeParam);
}
- public AndConstraint NotRegisterSentMessageTypes()
+ public static void NotRegisterSentMessageTypes(SyntaxTree syntaxTree)
{
- this.CurrentAssertionChain
- .ForCondition(!this._syntaxString.Contains(".SendsMessage<"))
- .BecauseOf("expected no message types to be registered")
- .FailWith("Expected {context} to have no message type registrations{reason}, but found at least one. Actual syntax: {1}",
- this._syntaxString);
-
- return new(this);
+ Assert.DoesNotContain(".SendsMessage<", syntaxTree.ToString());
}
- public AndConstraint RegisterYieldedOutputType(string outputTypeParam)
+ public static void RegisterYieldedOutputType(SyntaxTree syntaxTree, string outputTypeParam)
{
+ string syntaxString = syntaxTree.ToString();
string expectedRegistration = $".YieldsOutput<{outputTypeParam}>()";
- this.CurrentAssertionChain
- .ForCondition(this._syntaxString.Contains(expectedRegistration))
- .BecauseOf($"expected output type {outputTypeParam} to be registered")
- .FailWith("Expected {context} to contain output type registration {0}{reason}, but it was not found. Actual syntax: {1}",
- expectedRegistration, this._syntaxString);
-
- return new(this);
+ Assert.Contains(expectedRegistration, syntaxString);
}
- public AndConstraint RegisterYieldedOutputType(bool globalQualified = true)
+ public static void RegisterYieldedOutputType(SyntaxTree syntaxTree, bool globalQualified = true)
{
Type outputType = typeof(TOutput);
string outputTypeParam = globalQualified ? $"global::{outputType.FullName}" : outputType.Name;
- return this.RegisterYieldedOutputType(outputTypeParam);
+ RegisterYieldedOutputType(syntaxTree, outputTypeParam);
}
- public AndConstraint NotRegisterYieldedOutputTypes()
+ public static void NotRegisterYieldedOutputTypes(SyntaxTree syntaxTree)
{
- this.CurrentAssertionChain
- .ForCondition(!this._syntaxString.Contains(".YieldsOutput<"))
- .BecauseOf("expected no output types to be registered")
- .FailWith("Expected {context} to have no output type registrations{reason}, but found at least one. Actual syntax: {1}",
- this._syntaxString);
-
- return new(this);
+ Assert.DoesNotContain(".YieldsOutput<", syntaxTree.ToString());
}
- private AndConstraint ContainPartialDeclaration(int level, int index, string className)
+ private static void ContainPartialDeclaration(int level, int index, string className)
{
- this.CurrentAssertionChain
- .ForCondition(index > 0)
- .BecauseOf($"expected \"partial class {className}\" at nesting level {level}")
- .FailWith("Expected {context} to contain \"partial class {0}\" at nesting level {1}{reason}, but it was not found. Actual syntax: {2}",
- className, level, this._syntaxString);
-
- return new(this);
+ Assert.True(index > 0, $"Expected to contain \"partial class {className}\" at nesting level {level}.");
}
- private AndConstraint DeclarePartialsInCorrectOrder(int prevIndex, int currIndex, string prevClass, string currClass)
+ private static void DeclarePartialsInCorrectOrder(int prevIndex, int currIndex, string prevClass, string currClass)
{
- this.CurrentAssertionChain
- .ForCondition(prevIndex < currIndex)
- .BecauseOf($"expected \"partial class {prevClass}\" before \"partial class {currClass}\"")
- .FailWith("Expected {context} to have \"partial class {0}\" before \"partial class {1}\"{reason}, but the order was incorrect. Actual syntax: {2}",
- prevClass, currClass, this._syntaxString);
-
- return new(this);
+ Assert.True(prevIndex < currIndex, $"Expected \"partial class {prevClass}\" before \"partial class {currClass}\".");
}
- public AndConstraint HaveHierarchy(params string[] expectedNesting)
+ public static void HaveHierarchy(SyntaxTree syntaxTree, params string[] expectedNesting)
{
if (expectedNesting.Length == 0)
{
- return new AndConstraint(this);
+ return;
}
+ string syntaxString = syntaxTree.ToString();
int[] indicies = new int[expectedNesting.Length];
for (int i = 0; i < expectedNesting.Length; i++)
{
- indicies[i] = this._syntaxString.IndexOf($"partial class {expectedNesting[i]}", StringComparison.Ordinal);
+ indicies[i] = syntaxString.IndexOf($"partial class {expectedNesting[i]}", StringComparison.Ordinal);
}
// Verify partial declarations are present
- AndConstraint runningResult = this.ContainPartialDeclaration(0, indicies[0], expectedNesting[0]);
+ ContainPartialDeclaration(0, indicies[0], expectedNesting[0]);
for (int i = 1; i < expectedNesting.Length; i++)
{
- runningResult = runningResult.And.ContainPartialDeclaration(i, indicies[i], expectedNesting[i])
- .And.DeclarePartialsInCorrectOrder(indicies[i - 1], indicies[i], expectedNesting[i - 1], expectedNesting[i]);
+ ContainPartialDeclaration(i, indicies[i], expectedNesting[i]);
+ DeclarePartialsInCorrectOrder(indicies[i - 1], indicies[i], expectedNesting[i - 1], expectedNesting[i]);
}
-
- return runningResult;
}
- public AndConstraint HaveNamespace()
+ public static void HaveNamespace(SyntaxTree syntaxTree)
{
- this.CurrentAssertionChain
- .ForCondition(this._syntaxString.Contains("namespace "))
- .BecauseOf("expected namespace declaration")
- .FailWith("Expected {context} to contain a namespace declaration{reason}, but it was found. Actual syntax: {0}",
- this._syntaxString);
-
- return new(this);
+ Assert.Contains("namespace ", syntaxTree.ToString());
}
- public AndConstraint NotHaveNamespace()
+ public static void NotHaveNamespace(SyntaxTree syntaxTree)
{
- this.CurrentAssertionChain
- .ForCondition(!this._syntaxString.Contains("namespace "))
- .BecauseOf("expected no namespace declaration")
- .FailWith("Expected {context} to not contain a namespace declaration{reason}, but it was found. Actual syntax: {0}",
- this._syntaxString);
-
- return new(this);
+ Assert.DoesNotContain("namespace ", syntaxTree.ToString());
}
}
-
-internal static class SyntaxTreeFluentExtensions
-{
- public static SyntaxTreeAssertions Should(this SyntaxTree syntaxTree) => new(syntaxTree, AssertionChain.GetOrCreate());
-}
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/AIAgentHostExecutorTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/AIAgentHostExecutorTests.cs
index e5c45ebe4e0..2818d230326 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/AIAgentHostExecutorTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/AIAgentHostExecutorTests.cs
@@ -7,7 +7,6 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
-using FluentAssertions;
using Microsoft.Agents.AI.Workflows.Execution;
using Microsoft.Agents.AI.Workflows.Specialized;
using Microsoft.Extensions.AI;
@@ -87,17 +86,17 @@ public async Task Test_AgentHostExecutor_AssignsStableMessageIdToContentfulStrea
// Assert
AgentResponseUpdateEvent[] updateEvents = testContext.Events.OfType().ToArray();
- updateEvents.Should().HaveCount(3);
- updateEvents[0].Update.MessageId.Should().BeEmpty();
+ Assert.Equal(3, updateEvents.Length);
+ Assert.Equal(string.Empty, updateEvents[0].Update.MessageId);
string? messageId = updateEvents[1].Update.MessageId;
- messageId.Should().NotBeNullOrEmpty();
- updateEvents.Skip(1).Should().OnlyContain(updateEvent => updateEvent.Update.MessageId == messageId);
+ Assert.False(string.IsNullOrEmpty(messageId));
+ Assert.All(updateEvents.Skip(1), updateEvent => Assert.True(updateEvent.Update.MessageId == messageId));
- AgentResponseEvent responseEvent = testContext.Events.OfType().Should().ContainSingle().Subject;
- ChatMessage responseMessage = responseEvent.Response.Messages.Should().ContainSingle().Subject;
- responseMessage.MessageId.Should().Be(messageId);
- responseMessage.Text.Should().Be("hello world");
+ AgentResponseEvent responseEvent = Assert.Single(testContext.Events.OfType());
+ ChatMessage responseMessage = Assert.Single(responseEvent.Response.Messages);
+ Assert.Equal(messageId, responseMessage.MessageId);
+ Assert.Equal("hello world", responseMessage.Text);
}
private static ChatMessage UserMessage => new(ChatRole.User, "Hello from User!") { AuthorName = "User" };
@@ -180,18 +179,18 @@ public async Task Test_AgentHostExecutor_ReassignsRolesIFFConfiguredAsync(bool e
// Act
await executor.Router.RouteMessageAsync(messages, testContext.BindWorkflowContext(executor.Id));
- Func act = async () => await executor.TakeTurnAsync(new(), testContext.BindWorkflowContext(executor.Id));
+ async Task actAsync() => await executor.TakeTurnAsync(new(), testContext.BindWorkflowContext(executor.Id));
// Assert
bool shouldThrow = includeOtherMessages && !executorSetting;
if (shouldThrow)
{
- await act.Should().ThrowAsync();
+ await Assert.ThrowsAsync(actAsync);
}
else
{
- await act.Should().NotThrowAsync();
+ Assert.Null(await Record.ExceptionAsync(actAsync));
}
}
@@ -250,8 +249,7 @@ public async Task Test_AgentHostExecutor_InterceptsRequestsIFFConfiguredAsync(bo
List