Skip to content

[file-diet] Refactor TestClassInfo.cs: Split 832-line class into focused modules #8517

@Evangelink

Description

@Evangelink

Overview

The file src/Adapter/MSTestAdapter.PlatformServices/Execution/TestClassInfo.cs has grown to 832 lines, making it harder to navigate and maintain. This task involves refactoring it into smaller, more focused files that separate distinct responsibilities.

Current State

  • File: src/Adapter/MSTestAdapter.PlatformServices/Execution/TestClassInfo.cs
  • Size: 832 lines
  • Language: C#
Structural Analysis

TestClassInfo manages the entire lifecycle of test class execution in MSTest:

  1. Class metadata and configuration (lines 21-251)

    • Properties: ClassType, Constructor, TestContextProperty, ClassInitializeMethod, ClassCleanupMethod, TestInitializeMethod, TestCleanupMethod
    • Collections: BaseClassInitMethods, BaseClassCleanupMethods, BaseTestInitializeMethodsQueue, BaseTestCleanupMethodsQueue
    • Timeout dictionaries for initialize/cleanup methods
  2. Class initialization orchestration (lines 268-529)

    • RunClassInitializeAsync() - main entry point for class initialization
    • GetResultOrRunClassInitializeAsync() - caching and STA thread handling
    • TryGetClonedCachedClassInitializeResult() - result cloning logic
    • InvokeInitializeMethodAsync() - individual initialize method invocation
  3. Class cleanup orchestration (lines 578-799)

    • ExecuteClassCleanupAsync() - main cleanup execution
    • RunClassCleanupAsync() - STA thread handling for cleanup
    • InvokeCleanupMethodAsync() - individual cleanup method invocation
  4. Utility methods (lines 806-831)

    • ResolveTestContext() - static helper for resolving TestContext property

The class also manages:

  • Concurrency control via _testClassExecuteSyncSemaphore
  • Result caching for class initialize
  • STA apartment state handling for both initialize and cleanup
  • Exception handling and wrapping
  • Execution context capturing for async locals propagation

Refactoring Strategy

Proposed File Splits

Based on the file's structure, split it into the following modules:

  1. TestClassInfo.cs (core class, ~200 lines)

    • Core class definition and properties
    • Constructor
    • Simple property accessors
    • Public API surface
    • Responsibility: Central metadata and configuration holder for test classes
  2. TestClassInitializer.cs (~250 lines)

    • RunClassInitializeAsync()
    • GetResultOrRunClassInitializeAsync()
    • TryGetClonedCachedClassInitializeResult()
    • InvokeInitializeMethodAsync()
    • All initialization-related logic including STA thread handling
    • Responsibility: Orchestrate class initialization lifecycle with caching and threading support
  3. TestClassCleanup.cs (~250 lines)

    • ExecuteClassCleanupAsync()
    • RunClassCleanupAsync()
    • InvokeCleanupMethodAsync()
    • All cleanup-related logic including STA thread handling
    • Responsibility: Orchestrate class cleanup lifecycle with threading support
  4. TestContextResolver.cs (~50 lines)

    • ResolveTestContext() static utility
    • Any future test context-related utilities
    • Responsibility: Resolve and validate TestContext property via reflection

Implementation approach: Use partial classes to maintain the existing public API while splitting the implementation across files. This is idiomatic in .NET and already used extensively in the MSTest codebase (e.g., Assert class has 33 partial files).

Implementation Guidelines

  1. Use partial classes: Declare TestClassInfo as internal sealed partial class TestClassInfo in each file
  2. Preserve Behavior: All existing functionality must work identically after the split
  3. Maintain Public API: Keep all public/internal members accessible with the same signatures
  4. Update Imports: Ensure each new file has the necessary using directives
  5. Test After Each Split: Run unit tests after each incremental change
  6. One File at a Time: Split one module at a time to make review easier
  7. Keep concurrency control: The _testClassExecuteSyncSemaphore should remain in the core TestClassInfo.cs file as it's shared across initialization and cleanup

Acceptance Criteria

  • Original file is split into 4 focused partial class files
  • Each new file is under 300 lines
  • All tests pass after refactoring (./build.sh -test on Linux/macOS or .uild.cmd -test on Windows)
  • No breaking changes to public or internal API
  • All using directives are correct in each file
  • File organization follows existing MSTest conventions

Priority: Medium
Effort: Medium (requires careful extraction while maintaining thread-safety and async behavior)
Expected Impact: Improved code navigability, easier maintenance, clearer separation of concerns between initialization and cleanup lifecycles

Generated by Daily File Diet · ● 5.1M ·

  • expires on May 24, 2026, 7:42 PM UTC

Metadata

Metadata

Labels

type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions