From 6a7090c2c26e7196b7fc92c893e950cc3b4df5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Thu, 19 Mar 2026 09:10:26 +0100 Subject: [PATCH 1/2] Improve doc for MSTEST0049 and TestContext Give example on how to use the cancellation token --- .../testing/mstest-analyzers/mstest0049.md | 50 +++++++++++++++++++ .../csharp-cancellation/CancellationToken.cs | 18 +++++++ .../CancellationTokenCtor.cs | 23 +++++++++ .../csharp-cancellation/project.csproj | 14 ++++++ ...esting-mstest-writing-tests-testcontext.md | 15 ++++++ 5 files changed, 120 insertions(+) create mode 100644 docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs create mode 100644 docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationTokenCtor.cs create mode 100644 docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj diff --git a/docs/core/testing/mstest-analyzers/mstest0049.md b/docs/core/testing/mstest-analyzers/mstest0049.md index 3911cb85704d0..6af4255a4a758 100644 --- a/docs/core/testing/mstest-analyzers/mstest0049.md +++ b/docs/core/testing/mstest-analyzers/mstest0049.md @@ -41,6 +41,56 @@ This rule triggers when: Use the provided code fixer to automatically pass the from to method calls that support cancellation. You can also manually update method calls to include `TestContext.CancellationToken` as a parameter. +### Example: TestContext property + +The following code triggers MSTEST0049 because `Task.Delay` and `HttpClient.GetAsync` accept a but none is passed: + +```csharp +[TestClass] +public class MyTestClass +{ + public TestContext TestContext { get; set; } + + [TestMethod] + public async Task TestMethod() + { + using var client = new HttpClient(); + // MSTEST0049: these calls accept a CancellationToken but none is passed + await Task.Delay(1000); + var response = await client.GetAsync("https://example.com"); + } +} +``` + +The fix is to pass `TestContext.CancellationToken` to each call: + +:::code language="csharp" source="../snippets/testcontext/csharp-cancellation/CancellationToken.cs"::: + +### Example: constructor injection (MSTest 3.6+) + +With constructor injection, use the `_testContext` field to access the cancellation token: + +:::code language="csharp" source="../snippets/testcontext/csharp-cancellation/CancellationTokenCtor.cs"::: + ## When to suppress warnings Suppress this warning if you intentionally don't want to support cancellation for specific operations, or if the operation should continue even when the test is cancelled. + +## Suppress a warning + +If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule. + +```csharp +#pragma warning disable MSTEST0049 +// The code that's violating the rule is on this line. +#pragma warning restore MSTEST0049 +``` + +To disable the rule for a file, folder, or project, set its severity to `none` in the [configuration file](../../../fundamentals/code-analysis/configuration-files.md). + +```ini +[*.{cs,vb}] +dotnet_diagnostic.MSTEST0049.severity = none +``` + +For more information, see [How to suppress code analysis warnings](../../../fundamentals/code-analysis/suppress-warnings.md). diff --git a/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs b/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs new file mode 100644 index 0000000000000..75396e3a4cde0 --- /dev/null +++ b/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs @@ -0,0 +1,18 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public class TestClassCancellationToken +{ + public TestContext TestContext { get; set; } + + [TestMethod] + [Timeout(5000, CooperativeCancellation = true)] + public async Task MyAsyncTest() + { + using var client = new HttpClient(); + var response = await client.GetAsync( + "https://example.com", TestContext.CancellationToken); + + Assert.IsTrue(response.IsSuccessStatusCode); + } +} diff --git a/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationTokenCtor.cs b/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationTokenCtor.cs new file mode 100644 index 0000000000000..64af084b53fb2 --- /dev/null +++ b/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationTokenCtor.cs @@ -0,0 +1,23 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public class TestClassCancellationTokenCtor +{ + private readonly TestContext _testContext; + + public TestClassCancellationTokenCtor(TestContext testContext) + { + _testContext = testContext; + } + + [TestMethod] + [Timeout(5000, CooperativeCancellation = true)] + public async Task MyAsyncTest() + { + using var client = new HttpClient(); + var response = await client.GetAsync( + "https://example.com", _testContext.CancellationToken); + + Assert.IsTrue(response.IsSuccessStatusCode); + } +} diff --git a/docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj b/docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj new file mode 100644 index 0000000000000..fad62f70c1440 --- /dev/null +++ b/docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj @@ -0,0 +1,14 @@ + + + + net10.0 + latest + enable + enable + + + + + + + diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md b/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md index 219bf852e373b..7c42a6dd7457f 100644 --- a/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md +++ b/docs/core/testing/unit-testing-mstest-writing-tests-testcontext.md @@ -84,6 +84,21 @@ The or methods to write custom messages directly to the test output. This is especially useful for debugging purposes, as it provides real-time logging information within your test execution context. +### Cancellation token + +The exposes a property that is signaled when the test times out or the test run is aborted. You should pass this token to async operations so that they can respond to cancellation cooperatively. This is especially important when using [Timeout](xref:Microsoft.VisualStudio.TestTools.UnitTesting.TimeoutAttribute) attributes. + +When is accessed as a property: + +:::code language="csharp" source="snippets/testcontext/csharp-cancellation/CancellationToken.cs"::: + +When is injected through the constructor (MSTest 3.6+): + +:::code language="csharp" source="snippets/testcontext/csharp-cancellation/CancellationTokenCtor.cs"::: + +> [!TIP] +> MSTest analyzer rule [MSTEST0049](mstest-analyzers/mstest0049.md) helps identify async calls where `TestContext.CancellationToken` should be passed. It also provides a code fixer to apply the change automatically. + ## Related analyzers The following analyzers help ensure proper usage of the `TestContext` class: From 16efb2f00adf1cc4f39b710588636e3b37184775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Thu, 19 Mar 2026 09:24:18 +0100 Subject: [PATCH 2/2] Fixes --- .../testcontext/csharp-cancellation/CancellationToken.cs | 3 +++ .../snippets/testcontext/csharp-cancellation/project.csproj | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs b/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs index 75396e3a4cde0..62478687a79a9 100644 --- a/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs +++ b/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs @@ -3,6 +3,9 @@ [TestClass] public class TestClassCancellationToken { + // MSTest automatically sets the TestContext property before each test runs. + // MSTest.Analyzers includes a diagnostic suppressor that removes CS8618 + // (non-nullable property uninitialized) for this property. public TestContext TestContext { get; set; } [TestMethod] diff --git a/docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj b/docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj index fad62f70c1440..8779dd17fa901 100644 --- a/docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj +++ b/docs/core/testing/snippets/testcontext/csharp-cancellation/project.csproj @@ -8,7 +8,7 @@ - +