Overview
The file src/TestFramework/TestFramework/Assertions/Assert.That.cs has grown to 1522 lines, making it difficult to navigate and maintain. It already lives in a partial class, which makes splitting it into logically grouped partial-class files straightforward without any breaking changes.
Current State
- File:
src/TestFramework/TestFramework/Assertions/Assert.That.cs
- Size: 1522 lines
- Language: C#
Structural Analysis
The file contains one public method (That) and 35 private static helpers organized around five distinct concerns:
- Public API (lines 1–125): The
That(Expression<Func<bool>>) extension method and its supporting constants/sentinels.
- Expression evaluation (lines 126–481):
EvaluateExpression, CreateEvaluationCache, RequiresSinglePassEvaluation, EvaluateAllSubExpressions, TryEvaluateShortCircuitBinary, TryEvaluateCoalesce, TryEvaluateConditional.
- Expression replacement/simplification (lines 483–611):
ReplaceSubExpressionsWithConstants, ReplaceChildWithConstant.
- Detail/variable extraction (lines 580–874):
ExtractDetails, ExtractVariablesFromExpression, HandleArrayIndexExpression, AddMemberExpressionToDetails, HandleMethodCallExpression, TryAddExpressionValue, TranslateFailureSentinel.
- Text formatting & cleaning utilities (lines 875–1522):
GetCleanMemberName, GetIndexArgumentDisplay, IsVariableReference, IsSimpleExpression, FormatValue, CleanExpressionText, RemoveAnonymousTypeWrappers, CleanListInitializers, TryMatchListInitPattern, CleanTypeName, CleanParentheses, RemoveOuterParentheses, CleanExcessiveParentheses, RemoveCompilerGeneratedWrappers, TryRemoveWrapper, IsFuncOrActionType, CompilerGeneratedDisplayClassRegex.
Refactoring Strategy
Because AssertExtensions is already a partial class, no public API changes are needed — simply split the private helpers into new files in the same Assertions/ folder.
Proposed File Splits
-
Assert.That.cs (keep, shrink to ~120 lines)
- Contents: namespace/class declaration, constants,
FailedToEvaluateSentinel, the public That extension method.
- Responsibility: Public API surface — the single entry point for callers.
-
Assert.That.ExpressionEvaluator.cs (new, ~360 lines)
- Contents:
EvaluateExpression, CreateEvaluationCache, RequiresSinglePassEvaluation, EvaluateAllSubExpressions, TryEvaluateShortCircuitBinary, TryEvaluateCoalesce, TryEvaluateConditional.
- Responsibility: Recursively walk and evaluate LINQ expression trees.
-
Assert.That.ExpressionReplacer.cs (new, ~130 lines)
- Contents:
ReplaceSubExpressionsWithConstants, ReplaceChildWithConstant.
- Responsibility: Substitute evaluated sub-expressions back into the tree for display simplification.
-
Assert.That.DetailExtractor.cs (new, ~295 lines)
- Contents:
ExtractDetails, ExtractVariablesFromExpression, HandleArrayIndexExpression, AddMemberExpressionToDetails, HandleMethodCallExpression, TryAddExpressionValue, TranslateFailureSentinel.
- Responsibility: Walk the expression tree to collect variable names and runtime values for the failure message.
-
Assert.That.ExpressionFormatter.cs (new, ~650 lines)
- Contents:
GetCleanMemberName, GetIndexArgumentDisplay, IsVariableReference, IsSimpleExpression, FormatValue, CleanExpressionText, RemoveAnonymousTypeWrappers, CleanListInitializers, TryMatchListInitPattern, CleanTypeName, CleanParentheses, RemoveOuterParentheses, CleanExcessiveParentheses, RemoveCompilerGeneratedWrappers, TryRemoveWrapper, IsFuncOrActionType, CompilerGeneratedDisplayClassRegex.
- Responsibility: Convert raw expression text and runtime values into human-readable diagnostic strings.
Implementation Guidelines
- Preserve Behavior: All existing functionality must work identically after the split.
- Maintain Public API:
AssertExtensions is partial — no signatures change, no new public members.
- No Import Changes Needed: All files share the same namespace (
Microsoft.VisualStudio.TestTools.UnitTesting); no using updates required across the codebase.
- Test After Each Split: Run the MSTest unit-test suite after each incremental file move.
- One Group at a Time: Move one logical group per commit to keep diffs reviewable.
Acceptance Criteria
Priority: Medium
Effort: Medium (35 private methods, no cross-assembly dependencies, all changes contained to one directory)
Expected Impact: Improved code navigability, easier targeted testing, reduced merge conflicts on the Assert.That area
Generated by Daily File Diet · ● 2.2M · ◷
Overview
The file
src/TestFramework/TestFramework/Assertions/Assert.That.cshas grown to 1522 lines, making it difficult to navigate and maintain. It already lives in apartial class, which makes splitting it into logically grouped partial-class files straightforward without any breaking changes.Current State
src/TestFramework/TestFramework/Assertions/Assert.That.csStructural Analysis
The file contains one public method (
That) and 35 private static helpers organized around five distinct concerns:That(Expression<Func<bool>>)extension method and its supporting constants/sentinels.EvaluateExpression,CreateEvaluationCache,RequiresSinglePassEvaluation,EvaluateAllSubExpressions,TryEvaluateShortCircuitBinary,TryEvaluateCoalesce,TryEvaluateConditional.ReplaceSubExpressionsWithConstants,ReplaceChildWithConstant.ExtractDetails,ExtractVariablesFromExpression,HandleArrayIndexExpression,AddMemberExpressionToDetails,HandleMethodCallExpression,TryAddExpressionValue,TranslateFailureSentinel.GetCleanMemberName,GetIndexArgumentDisplay,IsVariableReference,IsSimpleExpression,FormatValue,CleanExpressionText,RemoveAnonymousTypeWrappers,CleanListInitializers,TryMatchListInitPattern,CleanTypeName,CleanParentheses,RemoveOuterParentheses,CleanExcessiveParentheses,RemoveCompilerGeneratedWrappers,TryRemoveWrapper,IsFuncOrActionType,CompilerGeneratedDisplayClassRegex.Refactoring Strategy
Because
AssertExtensionsis already apartial class, no public API changes are needed — simply split the private helpers into new files in the sameAssertions/folder.Proposed File Splits
Assert.That.cs(keep, shrink to ~120 lines)FailedToEvaluateSentinel, the publicThatextension method.Assert.That.ExpressionEvaluator.cs(new, ~360 lines)EvaluateExpression,CreateEvaluationCache,RequiresSinglePassEvaluation,EvaluateAllSubExpressions,TryEvaluateShortCircuitBinary,TryEvaluateCoalesce,TryEvaluateConditional.Assert.That.ExpressionReplacer.cs(new, ~130 lines)ReplaceSubExpressionsWithConstants,ReplaceChildWithConstant.Assert.That.DetailExtractor.cs(new, ~295 lines)ExtractDetails,ExtractVariablesFromExpression,HandleArrayIndexExpression,AddMemberExpressionToDetails,HandleMethodCallExpression,TryAddExpressionValue,TranslateFailureSentinel.Assert.That.ExpressionFormatter.cs(new, ~650 lines)GetCleanMemberName,GetIndexArgumentDisplay,IsVariableReference,IsSimpleExpression,FormatValue,CleanExpressionText,RemoveAnonymousTypeWrappers,CleanListInitializers,TryMatchListInitPattern,CleanTypeName,CleanParentheses,RemoveOuterParentheses,CleanExcessiveParentheses,RemoveCompilerGeneratedWrappers,TryRemoveWrapper,IsFuncOrActionType,CompilerGeneratedDisplayClassRegex.Implementation Guidelines
AssertExtensionsispartial— no signatures change, no new public members.Microsoft.VisualStudio.TestTools.UnitTesting); nousingupdates required across the codebase.Acceptance Criteria
Assertions/directory)IsFuncOrActionTypeandCompilerGeneratedDisplayClassRegexhelpers stay privatePriority: Medium
Effort: Medium (35 private methods, no cross-assembly dependencies, all changes contained to one directory)
Expected Impact: Improved code navigability, easier targeted testing, reduced merge conflicts on the
Assert.Thatarea