-
-
Save JayBazuzi/ffb7daa9450b2a647302 to your computer and use it in GitHub Desktop.
static class ValueTypeAssertions | |
{ | |
class C | |
{ | |
} | |
/// <summary> | |
/// Asserts that this type correctly implements "value" equality semantics. | |
/// </summary> | |
/// <param name="a">An example of T</param> | |
/// <param name="aPrime">Another T which should be the "same" as a</param> | |
/// <param name="b">Another T which should be different from a</param> | |
public static void HasValueEquality<T>(T a, T aPrime, T b) | |
{ | |
Assert.IsTrue(a.Equals(aPrime)); | |
Assert.IsTrue(a.GetHashCode().Equals(aPrime.GetHashCode())); | |
Assert.IsFalse(a.Equals(b)); | |
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode())); | |
Assert.IsFalse(a.Equals(null)); | |
Assert.IsFalse(a.Equals(new C())); | |
Assert.AreEqual(a, aPrime); | |
Assert.AreNotEqual(a, b); | |
} | |
} |
I often want to create small types with "value" equality semantics, as opposed to reference equality. C# makes me write a bunch of boilerplate code each time, but that doesn't mean I should have to write the same boilerplate tests. Instead, I want a single simple test that says "Assert that my type has value equality".
Then Should().Be()
should work. It uses Object.Equals
under the hood.
There's nothing wrong with Should().Be()
, but I want the whole assert you see above.
a.ShouldHaveValueEquality(anotherA, b); // asserts those 7 things
So it should assert that Equals
returns true
and GetHashCode
returns the same value for both objects?
It should assert the 7 things listed in my Gist.
Just forked and made the boilerplate to create a, aPrime, b less cumbersome. Next steps I think would be to create rich error messaging by either integrating with FluentAssertions or creating good messages with these asserts. I also think we may want to add an Assert to make sure it inherits from IEquatable.
I see that, but FA usually takes two objects and executes an assertion on that, but your gist uses 4 objects. Value Equality in .NET means that two objects return true
for Equals
, return the same value for GetHashCode
even though ReferenceEquals
returns false
. I could have an extension method that takes a factory lamba like @bgeihsgt just showed.
@bgeihsgt and @dennisdoomen: Here's another iteration. I split out equality from inequality, so you can deal with case-insensitive stuff:
new Foo("bar")
should equalnew Foo("BAR")
So what's so special about this example that Fluent Assertions'
a.Should().Be(aPrime)
doesn't do? The GetHashCode()?