Due the fact that the Assert static class has an AreEqual(object, object) the compiler is always able to find a valid match during compilation if a type changes on one side of the assertion. This means all failures must be found very late in the game (read: after compilation and tests have been run).
This is generally not desirable. Either the AreEqual(object, object) method should go away, or a more strict version of AreEqual should introduced. An ideal API might be
void Equality<T>(T expected, T actual) where T: IEquatable;
void Equality<T>(T expected, T actual, IEqualityComparer<T> comparer);
void SameObject(object expected, object actual); // performs ReferenceEquals(expected, actual)
With this triple alone, a test suite would cover 99% of equality tests without having to worry about the duck-typing mess we have today.
Setup a test with Assert.AreEqual(0, obj.value) with obj.value starting as an int, then change the type to TimeSpan (or whatever). It'll compile happily but fail when tests are run.
In a tiny project this is not a major issue, but in a large project where compilation take 45+ minutes and test runs can last an hour or more, this is a major time waster.
.NET solutions not using duck-typing.
MSTest uses duck-typing because ... ?
Windows 10, Visual Studio 2017, NetFx 4.6.2, stock MSTest nuget packages.
@pvlakshm yeah sure, the unforunate part is a custom assertion is private and not shared as part of the core library; meaning other adopters of the library do not benefit. Additionally, the flawed (by C# 4.5+ standards) design remains and is too easy for a consumer to adopt - which raises the cost of accepting contributions because now I have _another thing_ to check for in every code review.
Honestly, this library is getting old. Have a "mode shift" (whereby old features were disabled and newer ones enabled) by configuration would be a huge benefit.
@whoisj: Would the below API from here work?
AreEqual<T>(T expected, T actual)
You could mandate the use of this as opposed to the more general AreEqual(object, object). Agreed that this could be changed but pulling it out would be a breaking change.
@abhitejJohn how does the comparison in that method work?
Lacking the where T: IComparable<T> or the third parameter IEqualityComparer<T> comparer makes me slightly concerned. In generaly, yes it is better then AreEqual(object, object) but it'll default back to (object, object) if !(T is IComparable<T>), no?
Breaking changes aren't that concerning when they happen at the ABI signature layer and at major milestones because consumers get build failures during compilation stages, It's the failures that come after build + test (or worse after release to customers) which cause heartburn.
Yeah, that's odd these APIs don't accept an IComparable<T>(we might need to revisit the default set of assertion APIs - @pvlakshm, @harshjain2). We eventually just do an object.Equals(). I'm not sure what you mean by defaulting back but as long as the API called is AreEqual<T>(T,T) if any of the parameters passed in is not T then it would be a build break. Hope that answers the query.
Yup, we can consider deprecating this in the next major milestone.
@abhitejJohn while I agree the AreEqual<T>(T,T) solves the duck typing problem, it does not necessarily solve the equality problem. C# Object.Equals(Object) method only tests reference equality. It is identical to ReferenceEquals(Object, Object), or in C (void *)pt31 == (void *)prt2;
Please keep me in the loop as this is a major headache for me. I've been asked to use the MSTest framework in preference to NUint/XUnit and this is has been causing test escapes and unexpected failures with every set of tests I've converted.
Thanks! :smile:
Assert.AreEqual<T> is not good enough due to type inference as well: if you make the type explicit on the call, most tools will (correctly) point out that you are being redundant and suggest removing the type.
Having the object version is terrible design after generics was introduced and should definitely be removed, or we'll never have proper compile-time safety.
I've also run though the same problem OP describes multiple times so having this corrected would be incredibly useful.
When is this going to be addressed? In many cases an overload with IEqualityComparer<T> is required.
Thanks folks. Would you mind giving the issue a 馃憤 and we'll prioritize this. Sounds like we'd want to mark the API as obsolete for a few release so users are aware and remove it in the next major.
/cc: @nohwnd
Most helpful comment
Assert.AreEqual<T>is not good enough due to type inference as well: if you make the type explicit on the call, most tools will (correctly) point out that you are being redundant and suggest removing the type.Having the
objectversion is terrible design after generics was introduced and should definitely be removed, or we'll never have proper compile-time safety.I've also run though the same problem OP describes multiple times so having this corrected would be incredibly useful.