From 9fe5b829ddc481481d8132b09b91ce02d5845f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Tue, 7 Jul 2026 05:47:42 +0200 Subject: [PATCH] test: add edge case tests for MSTEST0020/0021 analyzers Add 3 edge-case tests documenting existing analyzer/fixer behavior: PreferConstructorOverTestInitializeAnalyzer (MSTEST0020): - WhenTestInitializeMethodInNonTestClass_Diagnostic: analyzer fires on a [TestInitialize] method in a class without [TestClass]; fixer replaces it with a constructor carrying its body. - WhenTestClassHasOnlyParameterizedCtorAndTestInitialize_CodeFix_MergesIntoParameterizedCtor: fixer merges the body into the first non-static constructor even when it is parameterized. PreferDisposeOverTestCleanupAnalyzer (MSTEST0021): - WhenTestCleanupMethodInNonTestClass_Diagnostic: analyzer fires on a [TestCleanup] method in a class without [TestClass]; fixer adds IDisposable and creates a Dispose() method. Fixes #9597, #9663, #9648 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- ...structorOverTestInitializeAnalyzerTests.cs | 78 +++++++++++++++++++ ...eferDisposeOverTestCleanupAnalyzerTests.cs | 33 ++++++++ 2 files changed, 111 insertions(+) diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs index d6a1f2d64e..5d2ee0bc71 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs @@ -404,6 +404,84 @@ private void SomePrivateMethod() await VerifyCS.VerifyCodeFixAsync(code, fixedCode); } + [TestMethod] + public async Task WhenTestInitializeMethodInNonTestClass_Diagnostic() + { + // The analyzer fires regardless of whether the containing class has [TestClass], + // and the fixer replaces the method with a constructor carrying its body. + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public class MyClass + { + [TestInitialize] + public void [|MyInit|]() + { + int x = 1; + } + } + """; + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public class MyClass + { + public MyClass() + { + int x = 1; + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + + [TestMethod] + public async Task WhenTestClassHasOnlyParameterizedCtorAndTestInitialize_CodeFix_MergesIntoParameterizedCtor() + { + // The fixer merges the TestInitialize body into the first non-static constructor found, + // even when that constructor has parameters and there is no default constructor. + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private int _x; + private int _y; + + public MyTestClass(int y) + { + _y = y; + } + + [TestInitialize] + public void [|MyTestInit|]() + { + _x = 1; + } + } + """; + string fixedCode = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private int _x; + private int _y; + + public MyTestClass(int y) + { + _y = y; + _x = 1; + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + [TestMethod] public async Task WhenTestClassHasTestInitializeWithMultiLineBody_PreservesIndentation() { diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs index 1627e30caf..02ebee0752 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferDisposeOverTestCleanupAnalyzerTests.cs @@ -381,6 +381,39 @@ public class MyTestClass } #endif + [TestMethod] + public async Task WhenTestCleanupMethodInNonTestClass_Diagnostic() + { + // The analyzer fires regardless of whether the containing class has [TestClass], + // and the fixer adds IDisposable to the base list and replaces the method with Dispose(). + string code = """ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public class MyClass + { + [TestCleanup] + public void [|MyCleanup|]() + { + int x = 1; + } + } + """; + string fixedCode = """ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public class MyClass : IDisposable + { + public void Dispose() + { + int x = 1; + } + } + """; + + await VerifyCS.VerifyCodeFixAsync(code, fixedCode); + } + [TestMethod] public async Task WhenTestClassHasTestCleanupWithMultiLineBody_PreservesIndentation() {