π― Repository Quality Improvement Report β Exception Handling and Error Recovery Patterns
Analysis Date: 2026-05-21
Focus Area: Exception Handling and Error Recovery Patterns
Strategy Type: Custom (Reuse-inspired deep dive)
Executive Summary
This analysis examined exception handling patterns across the microsoft/testfx repository (2,919 C# source files). The repository demonstrates strong exception handling foundations with 1,249 ConfigureAwait usages, 82 exception filters, and 211 nameof usages in exceptions. However, several modernization opportunities and consistency gaps exist:
Key Findings:
- Zero adoption of
ArgumentNullException.ThrowIfNull (.NET 6+ helper) despite 181 ArgumentNullException throws
- 5 instances of
throw ex; anti-pattern that lose stack traces (in ClassCleanupManager.cs)
- 50 async void methods creating unhandled exception risk vectors
- 199 hardcoded exception messages vs 121 localized ones (62% hardcoded rate)
- Minimal custom exception infrastructure: Only 9 custom exception types, 3 missing standard constructors
The codebase excels at async exception safety (1,249 ConfigureAwait calls) and sophisticated exception filtering (82 when clauses). These strengths can be leveraged to address the identified gaps through targeted improvements.
Full Analysis Report
Focus Area: Exception Handling and Error Recovery Patterns
Current State Assessment
Metrics Collected:
| Metric |
Value |
Status |
| Total C# source files |
2,919 |
π |
| Files with catch blocks |
134 |
β
|
| Files with throw statements |
887 |
β
|
| Top exception thrown |
InvalidOperationException (266) |
β
|
| Custom exception types |
9 |
β οΈ |
| ConfigureAwait usage |
1,249 |
β
|
| Exception filters (when clauses) |
82 |
β
|
| ArgumentNullException.ThrowIfNull adoption |
0 |
β |
throw ex; anti-patterns |
5 |
β οΈ |
| Async void methods |
50 |
β οΈ |
| Exception documentation tags |
159 |
β οΈ |
| Hardcoded exception messages |
199 |
β οΈ |
| Localized exception messages |
121 |
β
|
Bare throw; (correct pattern) |
32 |
β
|
| ExceptionDispatchInfo usage |
9 |
β
|
| AggregateException handling |
42 |
β
|
Exception Type Distribution
Top 10 Exception Types Thrown:
- InvalidOperationException: 266
- ArgumentNullException: 181
- NotImplementedException: 171
- ArgumentException: 72
- NotSupportedException: 48
- ArgumentOutOfRangeException: 26
- PlatformNotSupportedException: 19
- TypeInspectionException: 17 (custom)
- AssertFailedException: 16 (custom)
- FormatException: 15
Custom Exception Types:
UnitTestAssertException (abstract base) β public API, properly serializable
AssertFailedException β two versions (TestFramework & MSTest.Engine)
AssertInconclusiveException β TestFramework assertion outcome
MSTestException β internal TestFramework exception
AdapterSettingsException β internal adapter configuration errors
TypeInspectionException β internal reflection failures
TestFailedException β internal test execution failures
InvalidManagedNameException β internal name parsing failures
MessageFormatException β internal message formatting errors
Findings
Strengths
-
Excellent Async Exception Safety β
- 1,249 ConfigureAwait(false) calls across 487 async methods
- Consistent pattern in analyzers, code fixes, and platform services
- Prevents deadlocks and context-switching issues
-
Sophisticated Exception Filtering β
- 82 exception filters using
catch (...) when (...) clauses
- Excellent example in Assert.AreEquivalent.Comparer.cs:
catch (Exception ex) when (ex is not OutOfMemoryException
and not StackOverflowException
and not UnitTestAssertException)
- Prevents catching non-recoverable exceptions (OutOfMemoryException, StackOverflowException)
-
Strong nameof Usage β
- 211 exceptions use
nameof for parameter names
- Refactoring-safe, compile-time checked parameter references
-
Advanced Exception Preservation β
- 9 ExceptionDispatchInfo usages for preserving stack traces
- AssertScope.cs properly aggregates multiple assertion failures
- Correct use of bare
throw; (32 instances) vs throw ex; (only 5)
-
Proper AggregateException Handling β
- 42 AggregateException usages, primarily in TestResult.cs and AssertScope.cs
- Correctly aggregates multiple assertion failures for scope-based assertions
Areas for Improvement
-
Zero Modern Null Validation Adoption β HIGH PRIORITY
- 181 ArgumentNullException throws but 0 uses of
ArgumentNullException.ThrowIfNull
- .NET 6+ provides
ArgumentNullException.ThrowIfNull(arg) helper
- Repository targets .NET 8, should leverage modern patterns
- Current pattern requires manual null checks + throw statements
-
Stack Trace Loss Anti-Pattern β οΈ HIGH PRIORITY
- 5 instances of
throw ex; in production code:
src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs:70
src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs:86
- Should use bare
throw; to preserve stack traces
- Affects debugging and error diagnosis
-
Async Void Methods (Unhandled Exception Risk) β οΈ MEDIUM PRIORITY
- 50 async void methods in codebase
- Unhandled exceptions in async void methods crash the process
- Most are in test code (with VSTHRD100 suppressions), but requires audit
- Best practice: async Task methods with proper exception handling
-
Incomplete Custom Exception Design β οΈ MEDIUM PRIORITY
AdapterSettingsException.cs: Missing parameterless constructor, innerException constructor
- Several custom exceptions lack standard constructor overloads
- Pattern inconsistency: TypeInspectionException has full constructors, others don't
- Impacts exception propagation and serialization scenarios
-
Hardcoded Exception Messages β οΈ MEDIUM PRIORITY
- 199 hardcoded vs 121 localized exception messages (62% hardcoded)
- Violates localization guidelines for user-facing errors
- Examples found across test infrastructure and platform services
- Should use resource strings for consistent localization
-
Limited Exception Documentation β οΈ LOW PRIORITY
- Only 159
<exception> XML documentation tags across 2,919 files
- Public API methods often lack exception documentation
- Makes it harder for consumers to understand error conditions
-
Exception-Related Technical Debt β οΈ LOW PRIORITY
π€ Suggested Improvement Tasks
The following actionable tasks address the findings above, prioritized by impact and effort.
Task 1: Adopt ArgumentNullException.ThrowIfNull for Null Validation
Priority: High
Estimated Effort: Medium
Impact: Modernization, code consistency, reduced boilerplate
Description:
Replace traditional null-check patterns with the modern .NET 6+ ArgumentNullException.ThrowIfNull helper across the codebase.
Current Pattern (181 occurrences):
if (parameter is null)
{
throw new ArgumentNullException(nameof(parameter));
}
Modern Pattern:
ArgumentNullException.ThrowIfNull(parameter);
Benefits:
- Single-line null validation
- Consistent with modern .NET idioms
- Reduces boilerplate by ~3 lines per validation
- Compile-time safety with nameof embedded in helper
Target Files: All files throwing ArgumentNullException (181 instances found)
Acceptance Criteria:
Task 2: Fix Stack Trace Loss Anti-Pattern in ClassCleanupManager
Priority: High
Estimated Effort: Small
Impact: Debugging, production diagnostics
Description:
Fix the 5 instances of throw ex; anti-pattern that lose original stack traces. This primarily affects ClassCleanupManager.cs which handles test class cleanup exceptions.
Affected Files:
src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs (lines 70, 86)
Current Anti-Pattern:
catch (Exception ex)
{
// ... processing ...
throw ex; // β Loses original stack trace
}
Correct Pattern:
catch (Exception ex)
{
// ... processing ...
throw; // β
Preserves original stack trace
}
Impact: When test cleanup methods throw exceptions, stack traces currently reset to the rethrow point, obscuring the original failure location.
Acceptance Criteria:
Task 3: Audit and Eliminate Async Void Methods
Priority: Medium
Estimated Effort: Medium
Impact: Reliability, testability, exception handling
Description:
Audit the 50 async void methods in the codebase and convert to async Task where possible. Async void methods have unhandled exception semantics that crash the process, making them unsuitable outside event handlers.
Current State:
- 50 async void methods detected
- Most appear to be in test code with VSTHRD100 suppressions
- Some may be intentional (e.g., event handlers, UI callbacks)
Conversion Pattern:
// Before
public async void ProcessAsync()
{
await DoWorkAsync();
}
// After
public async Task ProcessAsync()
{
await DoWorkAsync();
}
Tasks:
- Identify all 50 async void methods
- Categorize: event handlers (keep) vs regular methods (convert)
- Convert non-event-handler methods to async Task
- For legitimate event handlers, add try-catch with logging
- Update callers to await Task-returning methods
Acceptance Criteria:
Task 4: Standardize Custom Exception Constructors
Priority: Medium
Estimated Effort: Small
Impact: API consistency, serialization, exception propagation
Description:
Add standard exception constructor overloads to custom exception types following the .NET exception design guidelines. Several custom exceptions (AdapterSettingsException, TestFailedException, etc.) lack the recommended constructors.
Standard Exception Pattern:
public class CustomException : Exception
{
public CustomException() { }
public CustomException(string message)
: base(message) { }
public CustomException(string message, Exception innerException)
: base(message, innerException) { }
}
Affected Custom Exceptions:
AdapterSettingsException.cs β Missing parameterless and innerException constructors
TestFailedException.cs β Missing constructors
InvalidManagedNameException.cs β Missing constructors
MSTestException.cs β Verify constructor completeness
Acceptance Criteria:
Task 5: Reduce Hardcoded Exception Messages via Localization
Priority: Medium
Estimated Effort: Large
Impact: Localization, user experience, message consistency
Description:
Reduce the 199 hardcoded exception messages by moving them to resource strings. Currently 62% of exception messages are hardcoded, violating the repository's localization guidelines.
Current Pattern (199 occurrences):
throw new InvalidOperationException("The test context is not available.");
Localized Pattern (121 occurrences):
throw new InvalidOperationException(Resources.TestContextNotAvailable);
Approach:
- Audit the 199 hardcoded messages
- Identify user-facing vs internal/debug messages
- Add resource entries for user-facing messages
- Update exception throw sites to use resources
- Run
dotnet msbuild <project>.csproj /t:UpdateXlf to regenerate .xlf files
Target Areas:
- TestFramework user-facing exceptions (high priority)
- Platform services adapter exceptions (medium priority)
- Internal exceptions can remain hardcoded if never user-visible
Acceptance Criteria:
π Historical Context
Previous Focus Areas
| Date |
Focus Area |
Type |
| 2026-04-30 |
MSTest Analyzer Ecosystem Health |
Custom |
| 2026-05-01 |
Technical Debt Comment Hygiene |
Custom |
| 2026-05-05 |
Warning Suppression Debt & Diagnostic Hygiene |
Custom |
| 2026-05-21 |
Exception Handling & Error Recovery Patterns |
Custom |
Statistics:
- Total quality improvement runs: 4
- Custom focus area rate: 100%
- Unique areas explored: 4
π― Recommendations
Immediate Actions (This Week)
-
Fix throw ex; Anti-Pattern β Priority: High
- 5 instances in ClassCleanupManager.cs
- Simple search-replace fix
- Immediate debugging improvement
-
Begin ArgumentNullException.ThrowIfNull Migration β Priority: High
- Start with high-traffic public APIs
- Update coding guidelines document
- Add to PR review checklist
Short-term Actions (This Month)
-
Audit Async Void Methods β Priority: Medium
- Categorize all 50 instances
- Convert non-event-handlers to async Task
- Document legitimate async void usage
-
Standardize Custom Exception Constructors β Priority: Medium
- Quick wins on 4-5 custom exception types
- Improves API consistency
- Enables better exception propagation
-
Begin Exception Message Localization β Priority: Medium
- Start with TestFramework public APIs
- Document localization policy for new code
- Reduce hardcoded rate incrementally
Generated by Repository Quality Improvement Agent
Next analysis: 2026-05-22 β Focus area selected based on diversity algorithm
Generated by Repository Quality Improver Β· β 3.7M Β· β·
π― Repository Quality Improvement Report β Exception Handling and Error Recovery Patterns
Analysis Date: 2026-05-21
Focus Area: Exception Handling and Error Recovery Patterns
Strategy Type: Custom (Reuse-inspired deep dive)
Executive Summary
This analysis examined exception handling patterns across the microsoft/testfx repository (2,919 C# source files). The repository demonstrates strong exception handling foundations with 1,249 ConfigureAwait usages, 82 exception filters, and 211 nameof usages in exceptions. However, several modernization opportunities and consistency gaps exist:
Key Findings:
ArgumentNullException.ThrowIfNull(.NET 6+ helper) despite 181 ArgumentNullException throwsthrow ex;anti-pattern that lose stack traces (in ClassCleanupManager.cs)The codebase excels at async exception safety (1,249 ConfigureAwait calls) and sophisticated exception filtering (82
whenclauses). These strengths can be leveraged to address the identified gaps through targeted improvements.Full Analysis Report
Focus Area: Exception Handling and Error Recovery Patterns
Current State Assessment
Metrics Collected:
throw ex;anti-patternsthrow;(correct pattern)Exception Type Distribution
Top 10 Exception Types Thrown:
Custom Exception Types:
UnitTestAssertException(abstract base) β public API, properly serializableAssertFailedExceptionβ two versions (TestFramework & MSTest.Engine)AssertInconclusiveExceptionβ TestFramework assertion outcomeMSTestExceptionβ internal TestFramework exceptionAdapterSettingsExceptionβ internal adapter configuration errorsTypeInspectionExceptionβ internal reflection failuresTestFailedExceptionβ internal test execution failuresInvalidManagedNameExceptionβ internal name parsing failuresMessageFormatExceptionβ internal message formatting errorsFindings
Strengths
Excellent Async Exception Safety β
Sophisticated Exception Filtering β
catch (...) when (...)clausesStrong nameof Usage β
nameoffor parameter namesAdvanced Exception Preservation β
throw;(32 instances) vsthrow ex;(only 5)Proper AggregateException Handling β
Areas for Improvement
Zero Modern Null Validation Adoption β HIGH PRIORITY
ArgumentNullException.ThrowIfNullArgumentNullException.ThrowIfNull(arg)helperStack Trace Loss Anti-Patternβ οΈ HIGH PRIORITY
throw ex;in production code:src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs:70src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs:86throw;to preserve stack tracesAsync Void Methods (Unhandled Exception Risk)β οΈ MEDIUM PRIORITY
Incomplete Custom Exception Designβ οΈ MEDIUM PRIORITY
AdapterSettingsException.cs: Missing parameterless constructor, innerException constructorHardcoded Exception Messagesβ οΈ MEDIUM PRIORITY
Limited Exception Documentationβ οΈ LOW PRIORITY
<exception>XML documentation tags across 2,919 filesException-Related Technical Debtβ οΈ LOW PRIORITY
TestExecutionContext.cs: "Filter exceptions that are to be considered as failures"TestDataSource.cs: "Change exception type to more specific one (Repository Quality: Analyzer Catalog Hygiene ImprovementsΒ #8086)"MethodInfoExtensions.cs: "Better to throw? or tolerate?"π€ Suggested Improvement Tasks
The following actionable tasks address the findings above, prioritized by impact and effort.
Task 1: Adopt
ArgumentNullException.ThrowIfNullfor Null ValidationPriority: High
Estimated Effort: Medium
Impact: Modernization, code consistency, reduced boilerplate
Description:
Replace traditional null-check patterns with the modern .NET 6+
ArgumentNullException.ThrowIfNullhelper across the codebase.Current Pattern (181 occurrences):
Modern Pattern:
Benefits:
Target Files: All files throwing ArgumentNullException (181 instances found)
Acceptance Criteria:
Task 2: Fix Stack Trace Loss Anti-Pattern in ClassCleanupManager
Priority: High
Estimated Effort: Small
Impact: Debugging, production diagnostics
Description:
Fix the 5 instances of
throw ex;anti-pattern that lose original stack traces. This primarily affectsClassCleanupManager.cswhich handles test class cleanup exceptions.Affected Files:
src/Adapter/MSTestAdapter.PlatformServices/Execution/ClassCleanupManager.cs(lines 70, 86)Current Anti-Pattern:
Correct Pattern:
Impact: When test cleanup methods throw exceptions, stack traces currently reset to the rethrow point, obscuring the original failure location.
Acceptance Criteria:
throw ex;instances with barethrow;Task 3: Audit and Eliminate Async Void Methods
Priority: Medium
Estimated Effort: Medium
Impact: Reliability, testability, exception handling
Description:
Audit the 50 async void methods in the codebase and convert to async Task where possible. Async void methods have unhandled exception semantics that crash the process, making them unsuitable outside event handlers.
Current State:
Conversion Pattern:
Tasks:
Acceptance Criteria:
Task 4: Standardize Custom Exception Constructors
Priority: Medium
Estimated Effort: Small
Impact: API consistency, serialization, exception propagation
Description:
Add standard exception constructor overloads to custom exception types following the .NET exception design guidelines. Several custom exceptions (AdapterSettingsException, TestFailedException, etc.) lack the recommended constructors.
Standard Exception Pattern:
Affected Custom Exceptions:
AdapterSettingsException.csβ Missing parameterless and innerException constructorsTestFailedException.csβ Missing constructorsInvalidManagedNameException.csβ Missing constructorsMSTestException.csβ Verify constructor completenessAcceptance Criteria:
Task 5: Reduce Hardcoded Exception Messages via Localization
Priority: Medium
Estimated Effort: Large
Impact: Localization, user experience, message consistency
Description:
Reduce the 199 hardcoded exception messages by moving them to resource strings. Currently 62% of exception messages are hardcoded, violating the repository's localization guidelines.
Current Pattern (199 occurrences):
Localized Pattern (121 occurrences):
Approach:
dotnet msbuild <project>.csproj /t:UpdateXlfto regenerate .xlf filesTarget Areas:
Acceptance Criteria:
π Historical Context
Previous Focus Areas
Statistics:
π― Recommendations
Immediate Actions (This Week)
Fix
throw ex;Anti-Pattern β Priority: HighBegin ArgumentNullException.ThrowIfNull Migration β Priority: High
Short-term Actions (This Month)
Audit Async Void Methods β Priority: Medium
Standardize Custom Exception Constructors β Priority: Medium
Begin Exception Message Localization β Priority: Medium
Generated by Repository Quality Improvement Agent
Next analysis: 2026-05-22 β Focus area selected based on diversity algorithm