shouldly / shouldly

Should testing for .NET—the way assertions should be!

Home Page:https://docs.shouldly.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"Should be...but was" messages can be unusable for C# record types and other default ToString representations

jnm2 opened this issue · comments

We should simply never print out the exact same string for both "should be" and "but was" when the failed assertion is that the objects didn't compare as equal. This happens a lot with C# record types that contain collections, where .Equals returns false because one or more fields fail reference equality but the ToString printout is the same.

Should be: R { A = 42, B = System.Collections.Immutable.ImmutableArray`1[System.Int32] }
But was: R { A = 42, B = System.Collections.Immutable.ImmutableArray`1[System.Int32] }

Just as bad is when the strings are different, but they are so long that it's nearly impossible to spot the difference. This happens frequently due to:

  • number of record properties
  • long substrings like System.Collections.Immutable.ImmutableArray`1[System.Int32] for types with default ToString()
  • nested records causing R { A = R2 { B = ... but where the difference doesn't appear on the first three (or ten) screens of horizontal scrolling

Goals

  1. When at all possible, bring the reader's attention directly to the property path that caused .Equals to fail. This requires some assumptions to be made about the implementation of Equals, but we can tell when it's compiler-generated at least.

    • When this is not possible, mention that Xyz.Equals returned false so that people know how the equality comparison was done.
    • If the total ToString is short enough on both expected and actual, and it's visually different, no need to add explanations or highlighting of the differing property paths.
  2. Use nicer formatting if ToString is compiler-generated, or if when we call it, we get something very long or something which doesn't differ between expected and actual.

    • Use multiline indentation?
    • Maybe replace long identical subportions with ... or similar?
    • Print out collections as R { SomeItems = [1, 2, 3] } using syntax similar to the [collection expressions] syntax coming in C# 12 (formerly called "collection literals": dotnet/csharplang#5354).
    • Find a way to show when equality fails due to references being different even when the string representation looks the same (including in [1, 2, 3] syntax for two different collections with the same contents)