diff --git a/docs/core/testing/mstest-analyzers/mstest0051.md b/docs/core/testing/mstest-analyzers/mstest0051.md new file mode 100644 index 0000000000000..08c15940a4c52 --- /dev/null +++ b/docs/core/testing/mstest-analyzers/mstest0051.md @@ -0,0 +1,69 @@ +--- +title: "MSTEST0051: Assert.Throws should contain only a single statement" +description: "Learn about code analysis rule MSTEST0051: Assert.Throws should contain only a single statement" +ms.date: 10/01/2025 +f1_keywords: +- MSTEST0051 +- AssertThrowsShouldContainSingleStatementAnalyzer +helpviewer_keywords: +- AssertThrowsShouldContainSingleStatementAnalyzer +- MSTEST0051 +author: Youssef1313 +ms.author: ygerges +ai-usage: ai-generated +--- +# MSTEST0051: Assert.Throws should contain only a single statement + +| Property | Value | +|-------------------------------------|------------------------------------------------------------------------------------------| +| **Rule ID** | MSTEST0051 | +| **Title** | Assert.Throws should contain only a single statement | +| **Category** | Usage | +| **Fix is breaking or non-breaking** | Non-breaking | +| **Enabled by default** | Yes | +| **Default severity** | Info | +| **Introduced in version** | 3.11.0 | +| **Is there a code fix** | No | + +## Cause + +A call to , , , or contains multiple statements in the action delegate. + +## Rule description + +To ensure that only the specific method call that is expected to throw an exception is tested, the action delegate passed to `Assert.Throws`, `Assert.ThrowsAsync`, `Assert.ThrowsExactly`, or `Assert.ThrowsExactlyAsync` should contain exactly one statement. Including multiple statements can lead to passing tests when the exception is thrown by a statement that is not intended to throw. If it's not the last statement in the action that is intended to throw, then the test has dead code. If it's the last statement, the intent should be clearly stated. + +## How to fix violations + +Refactor the test to ensure that the action delegate contains only the single statement that is expected to throw the exception. Move any setup code outside the assertion call. + +For example, change this: + +```csharp +[TestMethod] +public void TestMethod() +{ + var obj = new MyClass(); + Assert.ThrowsExactly(() => + { + obj.Initialize(); + obj.Execute(); // Only this should be inside the assertion + }); +} +``` + +To this: + +```csharp +[TestMethod] +public void TestMethod() +{ + var obj = new MyClass(); + obj.Initialize(); + Assert.ThrowsExactly(() => obj.Execute()); +} +``` + +## When to suppress warnings + +Don't suppress warnings from this rule. Including multiple statements in the action delegate can make it unclear which operation is being tested and can lead to passing tests when the original intent is violated. diff --git a/docs/core/testing/mstest-analyzers/mstest0052.md b/docs/core/testing/mstest-analyzers/mstest0052.md new file mode 100644 index 0000000000000..6031b203fc76f --- /dev/null +++ b/docs/core/testing/mstest-analyzers/mstest0052.md @@ -0,0 +1,76 @@ +--- +title: "MSTEST0052: Avoid passing an explicit 'DynamicDataSourceType' and use the default auto detect behavior" +description: "Learn about code analysis rule MSTEST0052: Avoid passing an explicit 'DynamicDataSourceType' and use the default auto detect behavior" +ms.date: 10/01/2025 +f1_keywords: +- MSTEST0052 +- AvoidExplicitDynamicDataSourceTypeAnalyzer +helpviewer_keywords: +- AvoidExplicitDynamicDataSourceTypeAnalyzer +- MSTEST0052 +author: Youssef1313 +ms.author: ygerges +ai-usage: ai-generated +--- +# MSTEST0052: Avoid passing an explicit 'DynamicDataSourceType' and use the default auto detect behavior + +| Property | Value | +|-------------------------------------|--------------------------------------------------------------------------------------------| +| **Rule ID** | MSTEST0052 | +| **Title** | Avoid passing an explicit 'DynamicDataSourceType' and use the default auto detect behavior | +| **Category** | Usage | +| **Fix is breaking or non-breaking** | Non-breaking | +| **Enabled by default** | Yes | +| **Default severity** | Warning | +| **Introduced in version** | 3.11.0 | +| **Is there a code fix** | Yes | + +## Cause + +A explicitly specifies or instead of using the default . + +## Rule description + +Starting with MSTest 3.8, `DynamicDataSourceType.AutoDetect` is the default value for the `DynamicDataSourceType` parameter in the `DynamicDataAttribute` constructor. This enhancement automatically detects whether the data source is a property, method, or field, eliminating the need to explicitly specify the source type. Using `AutoDetect` makes the code more maintainable and reduces verbosity. + +## How to fix violations + +Remove the explicit `DynamicDataSourceType` parameter from the `DynamicData` attribute and let the framework auto-detect the source type. + +For example, change this: + +```csharp +public static IEnumerable TestData { get; } = new[] +{ + new object[] { 1, 2, 3 }, + new object[] { 4, 5, 9 } +}; + +[TestMethod] +[DynamicData(nameof(TestData), DynamicDataSourceType.Property)] +public void TestMethod(int a, int b, int expected) +{ + Assert.AreEqual(expected, a + b); +} +``` + +To this: + +```csharp +public static IEnumerable TestData { get; } = new[] +{ + new object[] { 1, 2, 3 }, + new object[] { 4, 5, 9 } +}; + +[TestMethod] +[DynamicData(nameof(TestData))] +public void TestMethod(int a, int b, int expected) +{ + Assert.AreEqual(expected, a + b); +} +``` + +## When to suppress warnings + +Don't suppress warnings from this rule. Following the analyzer suggestion leads to less noise in the test code. diff --git a/docs/core/testing/mstest-analyzers/mstest0053.md b/docs/core/testing/mstest-analyzers/mstest0053.md new file mode 100644 index 0000000000000..b44274a561549 --- /dev/null +++ b/docs/core/testing/mstest-analyzers/mstest0053.md @@ -0,0 +1,66 @@ +--- +title: "MSTEST0053: Avoid using Assert methods with format parameters" +description: "Learn about code analysis rule MSTEST0053: Avoid using Assert methods with format parameters" +ms.date: 10/01/2025 +f1_keywords: +- MSTEST0053 +- AvoidAssertFormatParametersAnalyzer +helpviewer_keywords: +- AvoidAssertFormatParametersAnalyzer +- MSTEST0053 +author: Youssef1313 +ms.author: ygerges +ai-usage: ai-generated +--- +# MSTEST0053: Avoid using Assert methods with format parameters + +| Property | Value | +|-------------------------------------|------------------------------------------------------------------------------------------| +| **Rule ID** | MSTEST0053 | +| **Title** | Avoid using Assert methods with format parameters | +| **Category** | Usage | +| **Fix is breaking or non-breaking** | Non-breaking | +| **Enabled by default** | Yes | +| **Default severity** | Warning | +| **Introduced in version** | 3.11.0 | +| **Is there a code fix** | Yes | + +## Cause + +An assertion method call uses the `message` and `parameters` arguments for string formatting instead of using string interpolation. + +## Rule description + +Using the assertion overloads that accept `message` and `parameters` are no longer recommended. These overloads are removed in MSTest v4. It's advised to use string interpolation instead. + +## How to fix violations + +Replace calls that use message format parameters with string interpolation. + +For example, change this: + +```csharp +[TestMethod] +public void TestMethod() +{ + int expected = 5; + int actual = GetValue(); + Assert.AreEqual(expected, actual, "Expected {0} but got {1}", expected, actual); +} +``` + +To this: + +```csharp +[TestMethod] +public void TestMethod() +{ + int expected = 5; + int actual = GetValue(); + Assert.AreEqual(expected, actual, $"Expected {expected} but got {actual}"); +} +``` + +## When to suppress warnings + +Don't suppress warnings from this rule. These overloads are removed in MSTest v4 and are not recommended. diff --git a/docs/core/testing/mstest-analyzers/mstest0054.md b/docs/core/testing/mstest-analyzers/mstest0054.md new file mode 100644 index 0000000000000..d36f9effad832 --- /dev/null +++ b/docs/core/testing/mstest-analyzers/mstest0054.md @@ -0,0 +1,66 @@ +--- +title: "MSTEST0054: Use TestContext.CancellationToken instead of TestContext.CancellationTokenSource.Token" +description: "Learn about code analysis rule MSTEST0054: Use TestContext.CancellationToken instead of TestContext.CancellationTokenSource.Token" +ms.date: 10/01/2025 +f1_keywords: +- MSTEST0054 +- UseCancellationTokenPropertyAnalyzer +helpviewer_keywords: +- UseCancellationTokenPropertyAnalyzer +- MSTEST0054 +author: Youssef1313 +ms.author: ygerges +ai-usage: ai-generated +--- +# MSTEST0054: Use cancellation token from TestContext.CancellationToken + +| Property | Value | +|-------------------------------------|------------------------------------------------------------------------------------------| +| **Rule ID** | MSTEST0054 | +| **Title** | Use TestContext.CancellationToken instead of TestContext.CancellationTokenSource.Token | +| **Category** | Usage | +| **Fix is breaking or non-breaking** | Non-breaking | +| **Enabled by default** | Yes | +| **Default severity** | Info | +| **Introduced in version** | 3.11.0 | +| **Is there a code fix** | Yes | + +## Cause + +Accessing `CancellationToken` via `TestContext.CancellationTokenSource.Token` instead of using the `TestContext.CancellationToken` property. + +## Rule description + +MSTest provides a cancellation token through the `TestContext.CancellationToken` property. Accessing `TestContext.CancellationTokenSource` is not recommended, and it might be removed in a future release. It's also simpler to use `TestContext.CancellationToken` compared to `TestContext.CancellationTokenSource.Token`. + +## How to fix violations + +Use the `TestContext.CancellationToken` property instead of `TestContext.CancellationTokenSource.Token`. + +For example, change this: + +```csharp +public TestContext TestContext { get; set; } + +[TestMethod] +public async Task TestMethod() +{ + await Task.Delay(1000, TestContext.CancellationTokenSource.Token); +} +``` + +To this: + +```csharp +public TestContext TestContext { get; set; } + +[TestMethod] +public async Task TestMethod() +{ + await Task.Delay(1000, TestContext.CancellationToken); +} +``` + +## When to suppress warnings + +Don't suppress warnings from this rule. The use of `CancellationTokenSource` property is not recommended and might be removed in a future release. diff --git a/docs/core/testing/mstest-analyzers/mstest0055.md b/docs/core/testing/mstest-analyzers/mstest0055.md new file mode 100644 index 0000000000000..209244376392f --- /dev/null +++ b/docs/core/testing/mstest-analyzers/mstest0055.md @@ -0,0 +1,64 @@ +--- +title: "MSTEST0055: Do not ignore the return value of string methods" +description: "Learn about code analysis rule MSTEST0055: Do not ignore the return value of string methods" +ms.date: 10/01/2025 +f1_keywords: +- MSTEST0055 +- IgnoreStringMethodReturnValueAnalyzer +helpviewer_keywords: +- IgnoreStringMethodReturnValueAnalyzer +- MSTEST0055 +author: Youssef1313 +ms.author: ygerges +ai-usage: ai-generated +--- +# MSTEST0055: Do not ignore the return value of string methods + +| Property | Value | +|-------------------------------------|------------------------------------------------------------------------------------------| +| **Rule ID** | MSTEST0055 | +| **Title** | Do not ignore the return value of string methods | +| **Category** | Usage | +| **Fix is breaking or non-breaking** | Non-breaking | +| **Enabled by default** | Yes | +| **Default severity** | Warning | +| **Introduced in version** | 3.11.0 | +| **Is there a code fix** | No | + +## Cause + +A call to `string.Contains`, `string.StartsWith`, or `string.EndsWith` is made and its return value is ignored. + +## Rule description + +Those methods don't have any side effects and ignoring the return result is always wrong. It's more likely that the original intent of those calls are to assert that they are true. + +## How to fix violations + +Capture and use the return value from string methods, or use a proper assertion method. + +For example, change this: + +```csharp +[TestMethod] +public void TestMethod() +{ + string value = "Hello world"; + value.StartsWith("Hello"); +} +``` + +To this: + +```csharp +[TestMethod] +public void TestMethod() +{ + string value = "Hello world"; + Assert.IsTrue(value.StartsWith("Hello")); // or, Assert.StartsWith("Hello", value); +} +``` + +## When to suppress warnings + +Don't suppress warnings from this rule. Calling string methods without using their return value is always a bug or a dead code. diff --git a/docs/core/testing/mstest-analyzers/usage-rules.md b/docs/core/testing/mstest-analyzers/usage-rules.md index 081ae40c21f5e..50c3bc7503de9 100644 --- a/docs/core/testing/mstest-analyzers/usage-rules.md +++ b/docs/core/testing/mstest-analyzers/usage-rules.md @@ -3,7 +3,7 @@ title: MSTest Usage rules (code analysis) description: Learn about MSTest code analysis usage rules. author: evangelink ms.author: amauryleve -ms.date: 01/03/2024 +ms.date: 10/01/2025 --- # MSTest usage rules @@ -44,3 +44,8 @@ Identifier | Name | Description [MSTEST0048](mstest0048.md) | TestContextPropertyUsageAnalyzer | A fixture method (methods with , , , or ) accesses restricted properties. [MSTEST0049](mstest0049.md) | FlowTestContextCancellationTokenAnalyzer | A method call within a test context doesn't use the available from when the called method has a parameter or overload that accepts a . [MSTEST0050](mstest0050.md) | GlobalTestFixtureShouldBeValidAnalyzer | A global test fixture method (marked with `GlobalTestInitializeAttribute` or `GlobalTestCleanupAttribute`) doesn't follow the required layout or has invalid configuration. +[MSTEST0051](mstest0051.md) | AssertThrowsShouldContainSingleStatementAnalyzer | A call to , , , or contains multiple statements in the action delegate. +[MSTEST0052](mstest0052.md) | AvoidExplicitDynamicDataSourceTypeAnalyzer | A explicitly specifies or instead of using the default . +[MSTEST0053](mstest0053.md) | AvoidAssertFormatParametersAnalyzer | An assertion method call uses the `message` and `parameters` arguments for string formatting instead of using string interpolation. +[MSTEST0054](mstest0054.md) | UseCancellationTokenPropertyAnalyzer | Accessing `CancellationToken` via `TestContext.CancellationTokenSource.Token` instead of using the `TestContext.CancellationToken` property. +[MSTEST0055](mstest0055.md) | IgnoreStringMethodReturnValueAnalyzer | A call to `string.Contains`, `string.StartsWith`, or `string.EndsWith` is made and its return value is ignored. diff --git a/docs/navigate/devops-testing/toc.yml b/docs/navigate/devops-testing/toc.yml index 57a6ce1b45d6c..9356d2a89e479 100644 --- a/docs/navigate/devops-testing/toc.yml +++ b/docs/navigate/devops-testing/toc.yml @@ -227,6 +227,16 @@ items: href: ../../core/testing/mstest-analyzers/mstest0049.md - name: MSTEST0050 href: ../../core/testing/mstest-analyzers/mstest0050.md + - name: MSTEST0051 + href: ../../core/testing/mstest-analyzers/mstest0051.md + - name: MSTEST0052 + href: ../../core/testing/mstest-analyzers/mstest0052.md + - name: MSTEST0053 + href: ../../core/testing/mstest-analyzers/mstest0053.md + - name: MSTEST0054 + href: ../../core/testing/mstest-analyzers/mstest0054.md + - name: MSTEST0055 + href: ../../core/testing/mstest-analyzers/mstest0055.md - name: Test platforms items: - name: Microsoft.Testing.Platform