Skip to content

Commit 27ba8b1

Browse files
Upgrade to xunit.v3 (#8)
* Upgrade to xunit.v3 * Use Assert.Skip where applicable. --------- Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com>
1 parent 6b8c288 commit 27ba8b1

File tree

11 files changed

+128
-110
lines changed

11 files changed

+128
-110
lines changed

Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
3636
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
3737
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="$(System10Version)" />
38-
<PackageVersion Include="xunit" Version="2.9.2" />
39-
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.0" />
38+
<PackageVersion Include="xunit.v3" Version="1.1.0" />
39+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.2" />
4040
</ItemGroup>
4141
</Project>

ModelContextProtocol.sln

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ EndProject
3131
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B6FB2B28-D5DE-4654-BE9A-45E305DE4852}"
3232
ProjectSection(SolutionItems) = preProject
3333
Directory.Build.props = Directory.Build.props
34+
Directory.Packages.props = Directory.Packages.props
3435
global.json = global.json
3536
LICENSE = LICENSE
3637
logo.png = logo.png
38+
nuget.config = nuget.config
3739
README.MD = README.MD
3840
version.json = version.json
3941
EndProjectSection

tests/ModelContextProtocol.TestServer/Program.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Text;
2-
using System.Text.Json;
32
using ModelContextProtocol.Protocol.Messages;
43
using ModelContextProtocol.Protocol.Transport;
54
using ModelContextProtocol.Protocol.Types;

tests/ModelContextProtocol.Tests/Client/McpClientFactoryTests.cs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,28 @@ public class McpClientFactoryTests
1717
[Fact]
1818
public async Task CreateAsync_WithInvalidArgs_Throws()
1919
{
20-
await Assert.ThrowsAsync<ArgumentNullException>("serverConfig", () => McpClientFactory.CreateAsync((McpServerConfig)null!, _defaultOptions));
20+
await Assert.ThrowsAsync<ArgumentNullException>("serverConfig", () => McpClientFactory.CreateAsync((McpServerConfig)null!, _defaultOptions, cancellationToken: TestContext.Current.CancellationToken));
2121

22-
await Assert.ThrowsAsync<ArgumentNullException>("clientOptions", () => McpClientFactory.CreateAsync(
23-
new McpServerConfig()
22+
await Assert.ThrowsAsync<ArgumentNullException>("clientOptions", () => McpClientFactory.CreateAsync(new McpServerConfig()
2423
{
2524
Name = "name",
2625
Id = "id",
2726
TransportType = TransportTypes.StdIo,
28-
}, (McpClientOptions)null!));
27+
}, (McpClientOptions)null!, cancellationToken: TestContext.Current.CancellationToken));
2928

30-
await Assert.ThrowsAsync<ArgumentException>("serverConfig", () => McpClientFactory.CreateAsync(
31-
new McpServerConfig()
29+
await Assert.ThrowsAsync<ArgumentException>("serverConfig", () => McpClientFactory.CreateAsync(new McpServerConfig()
3230
{
3331
Name = "name",
3432
Id = "id",
3533
TransportType = "somethingunsupported",
36-
},
37-
_defaultOptions));
34+
}, _defaultOptions, cancellationToken: TestContext.Current.CancellationToken));
3835

39-
await Assert.ThrowsAsync<InvalidOperationException>(() => McpClientFactory.CreateAsync(
40-
new McpServerConfig()
36+
await Assert.ThrowsAsync<InvalidOperationException>(() => McpClientFactory.CreateAsync(new McpServerConfig()
4137
{
4238
Name = "name",
4339
Id = "id",
4440
TransportType = TransportTypes.StdIo,
45-
},
46-
_defaultOptions,
47-
(_, __) => null!));
41+
}, _defaultOptions, (_, __) => null!, cancellationToken: TestContext.Current.CancellationToken));
4842
}
4943

5044
[Fact]
@@ -68,7 +62,8 @@ public async Task CreateAsync_WithValidStdioConfig_CreatesNewClient()
6862
await using var client = await McpClientFactory.CreateAsync(
6963
serverConfig,
7064
_defaultOptions,
71-
(_, __) => new NopTransport());
65+
(_, __) => new NopTransport(),
66+
cancellationToken: TestContext.Current.CancellationToken);
7267

7368
// Assert
7469
Assert.NotNull(client);
@@ -91,7 +86,8 @@ public async Task CreateAsync_WithNoTransportOptions_CreatesNewClient()
9186
await using var client = await McpClientFactory.CreateAsync(
9287
serverConfig,
9388
_defaultOptions,
94-
(_, __) => new NopTransport());
89+
(_, __) => new NopTransport(),
90+
cancellationToken: TestContext.Current.CancellationToken);
9591

9692
// Assert
9793
Assert.NotNull(client);
@@ -114,7 +110,8 @@ public async Task CreateAsync_WithValidSseConfig_CreatesNewClient()
114110
await using var client = await McpClientFactory.CreateAsync(
115111
serverConfig,
116112
_defaultOptions,
117-
(_, __) => new NopTransport());
113+
(_, __) => new NopTransport(),
114+
cancellationToken: TestContext.Current.CancellationToken);
118115

119116
// Assert
120117
Assert.NotNull(client);
@@ -144,7 +141,8 @@ public async Task CreateAsync_WithSse_CreatesCorrectTransportOptions()
144141
await using var client = await McpClientFactory.CreateAsync(
145142
serverConfig,
146143
_defaultOptions,
147-
(_, __) => new NopTransport());
144+
(_, __) => new NopTransport(),
145+
cancellationToken: TestContext.Current.CancellationToken);
148146

149147
// Assert
150148
Assert.NotNull(client);
@@ -171,7 +169,7 @@ public async Task McpFactory_WithInvalidTransportOptions_ThrowsFormatException(s
171169
};
172170

173171
// act & assert
174-
await Assert.ThrowsAsync<ArgumentException>(() => McpClientFactory.CreateAsync(config, _defaultOptions));
172+
await Assert.ThrowsAsync<ArgumentException>(() => McpClientFactory.CreateAsync(config, _defaultOptions, cancellationToken: TestContext.Current.CancellationToken));
175173
}
176174

177175
private sealed class NopTransport : IClientTransport
@@ -191,7 +189,7 @@ public Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancella
191189
{
192190
switch (message)
193191
{
194-
case JsonRpcRequest request:
192+
case JsonRpcRequest:
195193
_channel.Writer.TryWrite(new JsonRpcResponse
196194
{
197195
Id = ((JsonRpcRequest)message).Id,

tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using ModelContextProtocol.Client;
2-
using ModelContextProtocol.Configuration;
3-
using ModelContextProtocol.Protocol.Messages;
4-
using ModelContextProtocol.Protocol.Transport;
5-
using ModelContextProtocol.Protocol.Types;
62
using Microsoft.Extensions.AI;
73
using OpenAI;
4+
using ModelContextProtocol.Protocol.Types;
5+
using ModelContextProtocol.Protocol.Messages;
86
using System.Text.Json;
7+
using ModelContextProtocol.Configuration;
8+
using ModelContextProtocol.Protocol.Transport;
9+
using Xunit.Sdk;
910

1011
namespace ModelContextProtocol.Tests;
1112

@@ -61,8 +62,8 @@ public async Task ListTools_Stdio(string clientId)
6162

6263
// act
6364
await using var client = await _fixture.CreateClientAsync(clientId);
64-
var tools = await client.ListToolsAsync().ToListAsync();
65-
var aiFunctions = await client.GetAIFunctionsAsync();
65+
var tools = await client.ListToolsAsync(TestContext.Current.CancellationToken).ToListAsync(TestContext.Current.CancellationToken);
66+
var aiFunctions = await client.GetAIFunctionsAsync(TestContext.Current.CancellationToken);
6667

6768
// assert
6869
Assert.NotEmpty(tools);
@@ -102,9 +103,9 @@ public async Task CallTool_Stdio_ViaAIFunction_EchoServer(string clientId)
102103

103104
// act
104105
await using var client = await _fixture.CreateClientAsync(clientId);
105-
var aiFunctions = await client.GetAIFunctionsAsync();
106+
var aiFunctions = await client.GetAIFunctionsAsync(TestContext.Current.CancellationToken);
106107
var echo = aiFunctions.Single(t => t.Name == "echo");
107-
var result = await echo.InvokeAsync([new KeyValuePair<string, object?>("message", "Hello MCP!")]);
108+
var result = await echo.InvokeAsync([new KeyValuePair<string, object?>("message", "Hello MCP!")], TestContext.Current.CancellationToken);
108109

109110
// assert
110111
Assert.NotNull(result);
@@ -119,7 +120,7 @@ public async Task ListPrompts_Stdio(string clientId)
119120

120121
// act
121122
await using var client = await _fixture.CreateClientAsync(clientId);
122-
var prompts = await client.ListPromptsAsync().ToListAsync();
123+
var prompts = await client.ListPromptsAsync(TestContext.Current.CancellationToken).ToListAsync(TestContext.Current.CancellationToken);
123124

124125
// assert
125126
Assert.NotEmpty(prompts);
@@ -251,7 +252,7 @@ public async Task SubscribeResource_Stdio()
251252
await client.SubscribeToResourceAsync("test://static/resource/1", CancellationToken.None);
252253

253254
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we get at least one notification
254-
await Task.Delay(10000);
255+
await Task.Delay(10000, TestContext.Current.CancellationToken);
255256

256257
// assert
257258
Assert.True(counter > 0);
@@ -276,17 +277,17 @@ public async Task UnsubscribeResource_Stdio()
276277
await client.SubscribeToResourceAsync("test://static/resource/1", CancellationToken.None);
277278

278279
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we get at least one notification
279-
await Task.Delay(10000);
280+
await Task.Delay(10000, TestContext.Current.CancellationToken);
280281

281282
// reset counter
282283
int counterAfterSubscribe = counter;
283-
284+
284285
// unsubscribe
285286
await client.UnsubscribeFromResourceAsync("test://static/resource/1", CancellationToken.None);
286287
counter = 0;
287288

288289
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we would've gotten at least one notification
289-
await Task.Delay(10000);
290+
await Task.Delay(10000, TestContext.Current.CancellationToken);
290291

291292
// assert
292293
Assert.True(counterAfterSubscribe > 0);
@@ -340,7 +341,7 @@ public async Task GetCompletion_Stdio_PromptReference(string clientId)
340341
[Theory]
341342
[MemberData(nameof(GetClients))]
342343
public async Task Sampling_Stdio(string clientId)
343-
{
344+
{
344345
// Set up the sampling handler
345346
int samplingHandlerCalls = 0;
346347
await using var client = await _fixture.CreateClientAsync(clientId, new()
@@ -375,8 +376,8 @@ public async Task Sampling_Stdio(string clientId)
375376
{
376377
["prompt"] = "Test prompt",
377378
["maxTokens"] = 100
378-
}
379-
);
379+
},
380+
TestContext.Current.CancellationToken);
380381

381382
// assert
382383
Assert.NotNull(result);
@@ -423,8 +424,8 @@ public async Task Notifications_Stdio(string clientId)
423424
await using var client = await _fixture.CreateClientAsync(clientId);
424425

425426
// Verify we can send notifications without errors
426-
await client.SendNotificationAsync(NotificationMethods.RootsUpdatedNotification);
427-
await client.SendNotificationAsync("test/notification", new { test = true });
427+
await client.SendNotificationAsync(NotificationMethods.RootsUpdatedNotification, cancellationToken: TestContext.Current.CancellationToken);
428+
await client.SendNotificationAsync("test/notification", new { test = true }, TestContext.Current.CancellationToken);
428429

429430
// assert
430431
// no response to check, if no exception is thrown, it's a success
@@ -452,13 +453,17 @@ public async Task CallTool_Stdio_MemoryServer()
452453
ClientInfo = new() { Name = "IntegrationTestClient", Version = "1.0.0" }
453454
};
454455

455-
await using var client = await McpClientFactory.CreateAsync(serverConfig, clientOptions, loggerFactory: _fixture.LoggerFactory);
456+
await using var client = await McpClientFactory.CreateAsync(
457+
serverConfig,
458+
clientOptions,
459+
loggerFactory: _fixture.LoggerFactory,
460+
cancellationToken: TestContext.Current.CancellationToken);
456461

457462
// act
458463
var result = await client.CallToolAsync(
459464
"read_graph",
460-
[]
461-
);
465+
[],
466+
TestContext.Current.CancellationToken);
462467

463468
// assert
464469
Assert.NotNull(result);
@@ -471,14 +476,14 @@ public async Task CallTool_Stdio_MemoryServer()
471476
[Fact]
472477
public async Task GetAIFunctionsAsync_UsingEverythingServer_ToolsAreProperlyCalled()
473478
{
474-
if (s_openAIKey is null)
475-
{
476-
return; // Skip the test if the OpenAI key is not provided
477-
}
479+
SkipTestIfNoOpenAIKey();
478480

479481
// Get the MCP client and tools from it.
480-
await using var client = await McpClientFactory.CreateAsync(_fixture.EverythingServerConfig, _fixture.DefaultOptions); ;
481-
var mappedTools = await client.GetAIFunctionsAsync();
482+
await using var client = await McpClientFactory.CreateAsync(
483+
_fixture.EverythingServerConfig,
484+
_fixture.DefaultOptions,
485+
cancellationToken: TestContext.Current.CancellationToken);
486+
var mappedTools = await client.GetAIFunctionsAsync(TestContext.Current.CancellationToken);
482487

483488
// Create the chat client.
484489
using IChatClient chatClient = new OpenAIClient(s_openAIKey).AsChatClient("gpt-4o-mini")
@@ -495,7 +500,7 @@ public async Task GetAIFunctionsAsync_UsingEverythingServer_ToolsAreProperlyCall
495500
messages.Add(new(ChatRole.User, "Please call the echo tool with the string 'Hello MCP!' and output the response ad verbatim."));
496501

497502
// Call the chat client
498-
var response = await chatClient.GetResponseAsync(messages, new() { Tools = [.. mappedTools], Temperature = 0 });
503+
var response = await chatClient.GetResponseAsync(messages, new() { Tools = [.. mappedTools], Temperature = 0 }, TestContext.Current.CancellationToken);
499504

500505
// Assert
501506
Assert.Contains("Echo: Hello MCP!", response.Text);
@@ -504,10 +509,7 @@ public async Task GetAIFunctionsAsync_UsingEverythingServer_ToolsAreProperlyCall
504509
[Fact]
505510
public async Task SamplingViaChatClient_RequestResponseProperlyPropagated()
506511
{
507-
if (s_openAIKey is null)
508-
{
509-
return; // Skip the test if the OpenAI key is not provided
510-
}
512+
SkipTestIfNoOpenAIKey();
511513

512514
await using var client = await McpClientFactory.CreateAsync(_fixture.EverythingServerConfig, new()
513515
{
@@ -519,17 +521,22 @@ public async Task SamplingViaChatClient_RequestResponseProperlyPropagated()
519521
SamplingHandler = new OpenAIClient(s_openAIKey).AsChatClient("gpt-4o-mini").CreateSamplingHandler(),
520522
},
521523
},
522-
});
524+
}, cancellationToken: TestContext.Current.CancellationToken);
523525

524526
var result = await client.CallToolAsync("sampleLLM", new()
525527
{
526528
["prompt"] = "In just a few words, what is the most famous tower in Paris?",
527-
});
529+
}, TestContext.Current.CancellationToken);
528530

529531
Assert.NotNull(result);
530532
Assert.NotEmpty(result.Content);
531533
Assert.Equal("text", result.Content[0].Type);
532534
Assert.Contains("LLM sampling result:", result.Content[0].Text);
533535
Assert.Contains("Eiffel", result.Content[0].Text);
534536
}
537+
538+
private static void SkipTestIfNoOpenAIKey()
539+
{
540+
Assert.SkipWhen(s_openAIKey is null, "No OpenAI key provided. Skipping test.");
541+
}
535542
}

tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<PackageReference Include="Microsoft.NET.Test.Sdk" />
1919
<PackageReference Include="Moq" />
2020
<PackageReference Include="System.Linq.AsyncEnumerable" />
21-
<PackageReference Include="xunit" />
21+
<PackageReference Include="xunit.v3" />
2222
<PackageReference Include="xunit.runner.visualstudio">
2323
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2424
<PrivateAssets>all</PrivateAssets>

0 commit comments

Comments
 (0)