Skip to content

[test-improver] test: add edge case tests for MSTEST0020/0021 analyzers #9663

Description

@github-actions

Goal and Rationale

Both PreferConstructorOverTestInitializeAnalyzer (MSTEST0020) and PreferDisposeOverTestCleanupAnalyzer (MSTEST0021) contain no [TestClass] guard in their diagnostic logic — they fire whenever [TestInitialize] or [TestCleanup] is present on a qualifying method, regardless of whether the containing class has [TestClass]. Additionally, the MSTEST0020 fixer merges [TestInitialize] body into the first non-static constructor found — which may be a parameterized constructor. These behaviors are undocumented in tests.

Approach

Added 3 edge-case tests:

PreferConstructorOverTestInitializeAnalyzerTests (MSTEST0020) — +2 tests

  1. WhenTestInitializeMethodInNonTestClass_Diagnostic: verifies the analyzer fires on [TestInitialize] in a class without [TestClass], and the fixer generates a default constructor.
  2. WhenTestClassHasOnlyParameterizedCtorAndTestInitialize_CodeFix_MergesIntoParameterizedCtor: verifies the fixer merges [TestInitialize] body into a parameterized constructor when no default constructor exists — the fixer's first-non-static-ctor strategy applies regardless of constructor signature.

PreferDisposeOverTestCleanupAnalyzerTests (MSTEST0021) — +1 test
3. WhenTestCleanupMethodInNonTestClass_Diagnostic: verifies the analyzer fires on [TestCleanup] in a class without [TestClass], and the fixer adds IDisposable to the class base list and generates a Dispose method.

Coverage Impact

FileTests BeforeTests After
PreferConstructorOverTestInitializeAnalyzerTests1012
PreferDisposeOverTestCleanupAnalyzerTests1112

Trade-offs

These tests are purely additive, document existing behavior, and have no production code changes.

Test Status

Build clean (0 warnings, 0 errors). All 25 affected tests pass (25/25 on net8.0):

Test run summary: Passed!
total: 25
failed: 0
succeeded: 25

Reproducibility

./build.sh --restore
.dotnet/dotnet test test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj -f net8.0 --no-build -c Debug --filter "ClassName~PreferConstructorOverTestInitialize|ClassName~PreferDisposeOverTestCleanup"

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Test Improver workflow. · 181.4 AIC · ⌖ 31.8 AIC · ⊞ 13K · [◷]( · )

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/test-improver.md@main

Note

This was originally intended as a pull request, but GitHub Actions is not permitted to create or approve pull requests in this repository.
The changes have been pushed to branch test-assist/mstest0020-0021-edge-cases-b9ee5a3094d707ef.

Click here to create the pull request

To fix the permissions issue, go to SettingsActionsGeneral and enable Allow GitHub Actions to create and approve pull requests. See also: gh-aw FAQ

Show patch preview (154 of 154 lines)
From 918fa3907816265f65a007848a27f9e194a859ae Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Mon, 6 Jul 2026 23:28:44 +0000
Subject: [PATCH] test: add edge case tests for MSTEST0020/0021 analyzers
Add 3 edge-case tests:
PreferConstructorOverTestInitializeAnalyzer (MSTEST0020):
- WhenTestInitializeMethodInNonTestClass_Diagnostic: verifies the
analyzer fires on [TestInitialize] methods in classes that do not
carry [TestClass] (no guard in the analyzer).
- WhenTestClassHasOnlyParameterizedCtorAndTestInitialize_CodeFix_MergesIntoParameterizedCtor:
verifies the fixer merges TestInitialize body into the first
non-static constructor even when it is parameterized.
PreferDisposeOverTestCleanupAnalyzer (MSTEST0021):
- WhenTestCleanupMethodInNonTestClass_Diagnostic: verifies the
analyzer fires on [TestCleanup] methods in classes that do not
carry [TestClass] (no guard in the analyzer).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
...structorOverTestInitializeAnalyzerTests.cs | 72 +++++++++++++++++++
...eferDisposeOverTestCleanupAnalyzerTests.cs | 30 ++++++++
2 files changed, 102 insertions(+)
diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs
index d6a1f2d..00920c6 100644
--- a/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs+++ b/test/UnitTests/MSTest.Analyzers.UnitTests/PreferConstructorOverTestInitializeAnalyzerTests.cs@@ -404,6 +404,78 @@ private void SomePrivateMethod()
await VerifyCS.VerifyCodeFixAsync(code, fixedCode);
}
+ [TestMethod]+ public async Task WhenTestInitializeMethodInNonTestClass_Diagnostic()+ {+ string code = """+ using Microsoft.VisualStudio.TestTools.UnitTesting;++ public class MyClass+
... (truncated)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/agentic-workflowsGitHub agentic workflow definitions under .github/workflows/*.md.type/automationCreated or maintained by an agentic workflow.type/test-gapMissing or insufficient tests.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions