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..62478687a79a9 --- /dev/null +++ b/docs/core/testing/snippets/testcontext/csharp-cancellation/CancellationToken.cs @@ -0,0 +1,21 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[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] + [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..8779dd17fa901 --- /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: