Skip to content

Commit 2fe163b

Browse files
committed
Update copilot testing instructions
1 parent 69971d9 commit 2fe163b

1 file changed

Lines changed: 33 additions & 16 deletions

File tree

.github/copilot-instructions.md

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,22 +85,39 @@ The SDK consists of three main packages:
8585
- Test servers in `tests/ModelContextProtocol.Test*Server/` for integration scenarios
8686
- Filter manual tests with `[Trait("Execution", "Manual")]` - these require external dependencies
8787

88-
### Test Infrastructure and Helpers
89-
- **LoggedTest**: Base class for tests that need logging output captured to xUnit test output
90-
- Provides `ILoggerFactory` and `ITestOutputHelper` for test logging
91-
- Use when debugging or when tests need to verify log output
92-
- **TestServerTransport**: In-memory transport for testing client-server interactions without network I/O
93-
- **MockLoggerProvider**: For capturing and asserting on log messages
94-
- **XunitLoggerProvider**: Routes `ILogger` output to xUnit's `ITestOutputHelper`
95-
- **KestrelInMemoryTransport** (AspNetCore.Tests): In-memory Kestrel connection for HTTP transport testing without network stack
96-
97-
### Test Best Practices
98-
- Inherit from `LoggedTest` for tests needing logging infrastructure
99-
- Use `TestServerTransport` for in-memory client-server testing
100-
- Mock external dependencies (filesystem, HTTP clients) rather than calling real services
101-
- Use `CancellationTokenSource` with timeouts to prevent hanging tests
102-
- Dispose resources properly (servers, clients, transports) using `IDisposable` or `await using`
103-
- Run tests with: `dotnet test --filter '(Execution!=Manual)'`
88+
### Test Base Classes
89+
- **`LoggedTest`**: Base class that wires up `ILoggerFactory` with `XunitLoggerProvider` (test output) and `MockLoggerProvider` (log assertions). Inherit from this for any test needing logging.
90+
- **`ClientServerTestBase`**: Sets up in-memory client/server pair via `Pipe`. Override `ConfigureServices` to register tools/prompts/resources, then call `CreateMcpClientForServer()`. Handles async disposal automatically.
91+
- **`KestrelInMemoryTest`** (AspNetCore tests): Hosts ASP.NET Core with in-memory transport — no ports needed.
92+
- **`TestServerTransport`**: In-memory mock transport for testing client logic without a real server.
93+
94+
### Transport Selection in Tests
95+
- **Never use `WithStdioServerTransport()` in unit tests.** It reads from the test host's stdin, which cannot be closed, permanently leaking a thread pool thread per test.
96+
- For DI-only tests: `WithStreamServerTransport(Stream.Null, Stream.Null)`
97+
- For client/server interaction: inherit `ClientServerTestBase`
98+
- For client-only logic: use `TestServerTransport`
99+
- For HTTP/SSE: inherit `KestrelInMemoryTest`
100+
- For process lifecycle tests: `StdioClientTransport` (only when testing actual process behavior)
101+
102+
### Resource Management
103+
- **Always `await using` the `ServiceProvider`** when MCP server services are registered — `McpServerImpl` only implements `IAsyncDisposable`. Synchronous `using` throws at runtime.
104+
- **Always dispose clients and servers** — use `await using var client = ...`
105+
- **Use `TestContext.Current.CancellationToken`** for async MCP calls so xUnit can cancel on timeout.
106+
107+
### Timeouts
108+
- **Always use `TestConstants.DefaultTimeout`** (60s) instead of hardcoded values. CI machines are slower than dev workstations.
109+
- For HTTP polling operations use `TestConstants.HttpClientPollingTimeout` (2s).
110+
111+
### Synchronization
112+
- **Never use `Task.Delay` for synchronization.** Use `TaskCompletionSource`, `SemaphoreSlim`, or `Channel` so tests don't depend on timing.
113+
114+
### Background Logging
115+
- `ITestOutputHelper.WriteLine` throws after the test method returns. Background threads (process event handlers, async continuations) can outlive the test, causing unhandled exceptions that crash the test host.
116+
- Route logging through `LoggedTest.LoggerFactory``XunitLoggerProvider` already catches post-test exceptions.
117+
- If calling `ITestOutputHelper` directly from an event handler, wrap in try/catch for `InvalidOperationException`.
118+
119+
### Parallelism
120+
- Tests run in parallel by default. Apply `[Collection(nameof(DisableParallelization))]` to test classes that touch global state (e.g., `ActivitySource` listeners).
104121

105122
## Build and Development
106123

0 commit comments

Comments
 (0)