Skip to content

GlobalTestInitialize/Cleanup implementation gaps: incorrect docs, severity inconsistency, shared timeout config, misleading desc [Content truncated due to length] #9662

Description

@github-actions

🎯 Repository Quality Improvement Report — GlobalTestInitialize/Cleanup Implementation Gaps

Analysis Date: 2026-07-06 | Strategy: Custom

Executive Summary

The GlobalTestInitialize and GlobalTestCleanup attributes have four concrete implementation gaps. Most critically, GlobalTestInitializeAttribute.cs states "TimeoutAttribute isn't supported on methods with this attribute" — directly contradicted by TryGetTimeoutInfo in TypeCache.ClassInfo.cs (which reads [Timeout] from the method first) and by acceptance test GlobalTestInitialize_WhenTimeoutExpires_GlobalTestInitializeIsCanceled_AttributeTakesPrecedence.

Structurally, global fixtures share FixtureKind.TestInitialize / FixtureKind.TestCleanup enum values (and therefore <TestInitializeTimeout> / <TestCleanupTimeout> RunSettings keys) with per-test methods. There is no way to set a timeout specifically for global fixtures without also affecting all [TestInitialize] / [TestCleanup] methods.

On the analyzer side, MSTEST0050 uses DiagnosticSeverity.Error while all six peer fixture rules (MSTEST0008–0013) use Warning, and the description text in Resources.resx incorrectly says static classes are invalid — contradicted by the WhenGlobalTestInitializeInStaticClass_NoDiagnostic test.

Full Analysis Report

Metrics:

Metric Value Status
Peer fixture rules severity (MSTEST0008–0013) Warning
MSTEST0050 severity Error ❌ inconsistent
GlobalTestInitializeAttribute doc: "[Timeout] not supported" Present ❌ factually wrong
TryGetTimeoutInfo reads [Timeout] on GlobalTestInitialize Yes
Acceptance test for [Timeout] attribute on GlobalTestInitialize Exists
Dedicated FixtureKind values for Global fixtures None ⚠️ hidden coupling
MSTEST0050 description: "class shouldn't be static" In Resources.resx ❌ contradicts analyzer test

Findings:

  1. [HIGH] Incorrect [Timeout] documentationGlobalTestInitializeAttribute.cs claims [Timeout] is unsupported. Runtime (TypeCache.AssemblyInfo.cs line 97) calls TryGetTimeoutInfo(methodInfo, FixtureKind.TestInitialize), which (in TypeCache.ClassInfo.cs:197) first checks for [Timeout] on the method. Acceptance test GlobalTestInitialize_WhenTimeoutExpires_GlobalTestInitializeIsCanceled_AttributeTakesPrecedence verifies this end-to-end.

  2. [HIGH] MSTEST0050 severity mismatch — All 6 peer rules use Warning; MSTEST0050 uses Error. Hard build-break for GlobalTestInitialize signature errors while equivalent ClassInitialize mistakes only warn.

  3. [MEDIUM] No dedicated timeout config for global fixturesFixtureKind has no GlobalTestInitialize/GlobalTestCleanup values. TimeoutWhenExpiresTests.InfoByKind confirms: "globalTestInit" → "TestInitializeTimeout". Setting <TestInitializeTimeout> silently also controls GlobalTestInitialize.

  4. [MEDIUM] Description vs behavior inconsistencyResources.resx description: "The class shouldn't be 'static'". Analyzer test WhenGlobalTestInitializeInStaticClass_NoDiagnostic passes [TestClass] public static class as valid.

  5. [LOW] Single rule for two fixtures — ClassInitialize/ClassCleanup have separate MSTEST0010/0011. MSTEST0050 collapses both global fixtures into one rule and one message that doesn't indicate which attribute is wrong.


🤖 Suggested Improvement Tasks

Task 1: Correct GlobalTestInitializeAttribute docs for [Timeout]

Priority: High | Effort: Small

Remove the inaccurate sentence "In addition, TimeoutAttribute isn't supported on methods with this attribute" from GlobalTestInitializeAttribute.cs and replace it with documentation confirming [Timeout] IS supported (method-level attribute takes precedence over RunSettings global timeout, same as other fixture types).

File: src/TestFramework/TestFramework/Attributes/Lifecycle/Initialization/GlobalTestInitializeAttribute.cs


Task 2: Change MSTEST0050 severity from Error to Warning

Priority: High | Effort: Small

In GlobalTestFixtureShouldBeValidAnalyzer.cs, change DiagnosticSeverity.Error to DiagnosticSeverity.Warning to match MSTEST0008–0013. Update expected severity in GlobalTestFixtureShouldBeValidAnalyzerTests.cs.

File: src/Analyzers/MSTest.Analyzers/GlobalTestFixtureShouldBeValidAnalyzer.cs


Task 3: Add dedicated GlobalTestInitialize / GlobalTestCleanup entries to FixtureKind and MSTestSettings

Priority: Medium | Effort: Medium

  1. Add GlobalTestInitialize and GlobalTestCleanup to FixtureKind enum
  2. Add GlobalTestInitializeTimeout / GlobalTestCleanupTimeout to MSTestSettings, parsed from both RunSettings XML (<GlobalTestInitializeTimeout>) and testconfig.json (timeout:globalTestInitialize)
  3. Update TimeoutInfo.FromFixtureSettings switch to handle the new values (fall back to TestInitializeTimeout/TestCleanupTimeout when not set, for backward compat)
  4. Update TypeCache.AssemblyInfo.cs to use the new FixtureKind values
  5. Update TimeoutWhenExpiresTests.InfoByKind and add acceptance tests for the new settings

Files: FixtureKind.cs, TimeoutInfo.cs, MSTestSettings.cs, TypeCache.AssemblyInfo.cs, TimeoutWhenExpiresTests.cs


Task 4: Fix MSTEST0050 description — remove incorrect static-class restriction

Priority: Medium | Effort: Small

Remove the bullet "-The class shouldn't be 'static'" from GlobalTestFixtureShouldBeValidDescription in Resources.resx. The analyzer's own WhenGlobalTestInitializeInStaticClass_NoDiagnostic test confirms [TestClass] public static class is valid. Regenerate XLF files via dotnet msbuild src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj /t:UpdateXlf after editing.

File: src/Analyzers/MSTest.Analyzers/Resources.resx


Task 5: Split MSTEST0050 into separate GlobalTestInitialize and GlobalTestCleanup rules

Priority: Low | Effort: Medium

All peer fixture types have separate rules (MSTEST0008/0009, 0010/0011, 0012/0013). MSTEST0050 collapses both into one. Splitting into MSTEST0050 (GlobalTestInitializeShouldBeValid) and a new ID (GlobalTestCleanupShouldBeValid) enables distinct FixtureParameterMode settings if requirements diverge and produces more targeted error messages. MSTEST0050 stays for Initialize; the new rule targets Cleanup. Update DiagnosticIds.cs, Resources.resx, analyzer file(s), and unit tests.


📊 Previous Focus Areas

Date Focus Area
2026-07-03 test-context-api-surface-consistency
2026-07-02 cross-component-diagnostic-metadata-consistency
2026-07-01 preprocessor-symbol-hygiene
2026-06-30 mstest-sdk-runner-target-correctness
2026-06-29 async-exception-assertion-gaps

Next analysis: 2026-07-07

🤖 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 Repository Quality Improver workflow. · 172.6 AIC · ⌖ 10.3 AIC · ⊞ 10.2K · [◷]( · )

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repository-quality-improver.md@main
  • expires on Jul 8, 2026, 10:51 PM UTC

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions