Improve assertions error messages with structured format#7444
Open
Evangelink wants to merge 17 commits intomainfrom
Open
Improve assertions error messages with structured format#7444Evangelink wants to merge 17 commits intomainfrom
Evangelink wants to merge 17 commits intomainfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request modernizes assertion error messages by introducing a structured, multi-line format that improves readability and developer experience. The changes replace old-style concatenated messages with formatted parameter displays using raw string literals.
Changes:
- Introduced structured error message formatting with parameter names, expressions, and values on separate lines
- Added helper methods for value formatting, expression truncation, and redundancy detection
- Updated all assertion methods to use the new formatting approach
- Removed obsolete resource strings and added new simplified ones
- Updated all test expectations to match the new message format
Reviewed changes
Copilot reviewed 41 out of 41 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| Assert.cs | Core formatting infrastructure: FormatValue, FormatParameter, truncation logic |
| Assert.ThrowsException.cs | Updated to new structured format for exception type mismatches |
| Assert.StartsWith/EndsWith/Matches.cs | String assertion methods using new format |
| Assert.IsTrue/IsFalse.cs | Boolean assertion methods with condition parameter display |
| Assert.IsNull/IsNotNull.cs | Null checking assertions with value display |
| Assert.IsInstanceOfType/IsExactInstanceOfType.cs | Type checking with structured type comparison |
| Assert.IComparable.cs | Comparison assertions (greater/less than, positive/negative) |
| Assert.Count/Contains.cs | Collection assertions with expression parameters |
| Assert.AreSame.cs | Reference equality with hash code display for disambiguation |
| FrameworkMessages.resx | Resource string simplification and new message keys |
| xlf files | Localization files marked with untranslated entries |
| Test files | Updated expectations for all assertion error messages |
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsInstanceOfTypeTests.cs
Show resolved
Hide resolved
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsExactInstanceOfTypeTests.cs
Show resolved
Hide resolved
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreSame.cs
Show resolved
Hide resolved
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsExactInstanceOfTypeTests.cs
Show resolved
Hide resolved
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsTrueTests.cs
Show resolved
Hide resolved
a55c762 to
49018c6
Compare
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.cs
Outdated
Show resolved
Hide resolved
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.cs
Outdated
Show resolved
Hide resolved
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf
Show resolved
Hide resolved
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf
Show resolved
Hide resolved
49018c6 to
63e8257
Compare
Member
|
looks great |
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.StartsWith.cs
Show resolved
Hide resolved
Comment on lines
+12
to
+127
| public void MatchesRegex_WhenValueMatchesPattern_ShouldPass() | ||
| => Assert.MatchesRegex(@"\d+", "abc123"); | ||
|
|
||
| public void MatchesRegex_WhenValueDoesNotMatchPattern_ShouldFail() | ||
| { | ||
| Action action = () => Assert.MatchesRegex(@"\d+", "abc"); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage(""" | ||
| Assert.MatchesRegex failed. | ||
| String does not match expected pattern. | ||
| pattern: \d+ | ||
| value: "abc" | ||
| """); | ||
| } | ||
|
|
||
| public void DoesNotMatchRegex_WhenValueDoesNotMatchPattern_ShouldPass() | ||
| => Assert.DoesNotMatchRegex(@"\d+", "abc"); | ||
|
|
||
| public void DoesNotMatchRegex_WhenValueMatchesPattern_ShouldFail() | ||
| { | ||
| Action action = () => Assert.DoesNotMatchRegex(@"\d+", "abc123"); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage(""" | ||
| Assert.DoesNotMatchRegex failed. | ||
| String matches pattern but should not. | ||
| pattern: \d+ | ||
| value: "abc123" | ||
| """); | ||
| } | ||
|
|
||
| #endregion | ||
|
|
||
| #region MatchesRegex/DoesNotMatchRegex truncation and newline escaping | ||
|
|
||
| public void MatchesRegex_WithLongExpression_ShouldTruncateExpression() | ||
| { | ||
| string aVeryLongVariableNameThatExceedsOneHundredCharactersInLengthToTestTruncationBehaviorOfExpressionDisplayXYZ = "hello"; | ||
|
|
||
| Action action = () => Assert.MatchesRegex(@"\d+", aVeryLongVariableNameThatExceedsOneHundredCharactersInLengthToTestTruncationBehaviorOfExpressionDisplayXYZ); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage(""" | ||
| Assert.MatchesRegex failed. | ||
| String does not match expected pattern. | ||
| pattern: \d+ | ||
| value (aVeryLongVariableNameThatExceedsOneHundredCharactersInLengthToTestTruncationBehaviorOfExpressionDisp...): "hello" | ||
| """); | ||
| } | ||
|
|
||
| public void MatchesRegex_WithLongValue_ShouldTruncateValue() | ||
| { | ||
| string longValue = new string('x', 300); | ||
|
|
||
| Action action = () => Assert.MatchesRegex(@"\d+", longValue); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage($""" | ||
| Assert.MatchesRegex failed. | ||
| String does not match expected pattern. | ||
| pattern: \d+ | ||
| value (longValue): "{new string('x', 255)}... (302 chars) | ||
| """); | ||
| } | ||
|
|
||
| public void MatchesRegex_WithNewlineInValue_ShouldEscapeNewlines() | ||
| { | ||
| Action action = () => Assert.MatchesRegex(@"^\d+$", "hello\r\nworld"); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage(""" | ||
| Assert.MatchesRegex failed. | ||
| String does not match expected pattern. | ||
| pattern: ^\d+$ | ||
| value: "hello\r\nworld" | ||
| """); | ||
| } | ||
|
|
||
| public void DoesNotMatchRegex_WithLongExpression_ShouldTruncateExpression() | ||
| { | ||
| string aVeryLongVariableNameThatExceedsOneHundredCharactersInLengthToTestTruncationBehaviorOfExpressionDisplayXYZ = "abc123"; | ||
|
|
||
| Action action = () => Assert.DoesNotMatchRegex(@"\d+", aVeryLongVariableNameThatExceedsOneHundredCharactersInLengthToTestTruncationBehaviorOfExpressionDisplayXYZ); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage(""" | ||
| Assert.DoesNotMatchRegex failed. | ||
| String matches pattern but should not. | ||
| pattern: \d+ | ||
| value (aVeryLongVariableNameThatExceedsOneHundredCharactersInLengthToTestTruncationBehaviorOfExpressionDisp...): "abc123" | ||
| """); | ||
| } | ||
|
|
||
| public void DoesNotMatchRegex_WithLongValue_ShouldTruncateValue() | ||
| { | ||
| string longValue = new string('1', 300); | ||
|
|
||
| Action action = () => Assert.DoesNotMatchRegex(@"\d+", longValue); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage($""" | ||
| Assert.DoesNotMatchRegex failed. | ||
| String matches pattern but should not. | ||
| pattern: \d+ | ||
| value (longValue): "{new string('1', 255)}... (302 chars) | ||
| """); | ||
| } | ||
|
|
||
| public void DoesNotMatchRegex_WithNewlineInValue_ShouldEscapeNewlines() | ||
| { | ||
| Action action = () => Assert.DoesNotMatchRegex(@"hello", "hello\r\nworld"); | ||
| action.Should().Throw<AssertFailedException>() | ||
| .WithMessage(""" | ||
| Assert.DoesNotMatchRegex failed. | ||
| String matches pattern but should not. | ||
| pattern: hello | ||
| value: "hello\r\nworld" | ||
| """); | ||
| } | ||
|
|
||
| #endregion | ||
| } |
There was a problem hiding this comment.
All test methods in this new file are missing the [TestMethod] attribute. Without this attribute, none of these tests will be discovered and executed by the test runner.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.EndsWith.cs
Show resolved
Hide resolved
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix #7421