FluentAssertions: ShouldBeEquivalentTo method still invokes Object.Equals()? - c#

I have a class, let's call it Foo, that is a value type and hence overrides the Equals/GetHashCode() methods. In a separate test fixture, I want to assert that all the properties on Foo have been set properly, not just the properties used for equality. For this reason, my test assertion specifically uses the ShouldBeEquivalentTo method, which the documentation suggests will consider two objects to be equivalent if "both object graphs have equally named properties with the same value, irrespective of the type of those objects."
However, it appears that ShouldBeEquivalentTo invokes Foo.Equals method, gets a true result and then proceeds to short-circuit the reflection based property matching that ShouldBeEquivalentTo promises.
Is this expected behavior? If so, in inspecting the FA source, I saw no easy way to alter this behavior (IEquivalencyStep is declared internal). Are there any other ways to around this?
Edit:
Dennis: Yes, the two objects I'm comparing are of the same type. To summarize, I have overridden Equals on class Foo, but do not want FA to use this notion of equality for my unit tests.

I think you cannot alter behavior of this function, it assumes that if you override Equals - than you want comparison to be the same way. You can try the following function:
dto.ShouldHave().SharedProperties().EqualTo(foo);
Or you can implement in Foo class NativeEquals method which will be calling base.Equals() , and then use this method explicitly for comparison, it will work great for value types.

Related

How can I be sure that List.Contains works for a list of DataTables?

If I have this:
List<DataTable> listDataTables = functionToAddSomeDataTables();
and I want to do a comparison like this:
if(listDataTables.Contains(aDataTable))
{
//do something.
}
How can I know if it is comparing the reference or the schema or the content or all of the above?
Do I need to write my own IEquatable.Equals to make sure it works properly or can I trust that the built in .Equals for DataTable works as I would hope?
Is there a general rule or observation for knowing when .Contains, or similar comparisons are by reference or by value?
Thanks in advance :)
List<T>.Contains uses the object's object.Equals(object) method. Since DataTable's documentation says that its Equals was inherited from Object.Equals, the default Object.Equals implementation of reference comparison is what will be used. If you want the comparison by something else, include that equality comparer by using LINQ's Contains method.
(as an example, compare DataTable Methods and Decimal Methods: only Decimal lists Equals on the list on the left, and says "(Overrides ValueType.Equals(Object).)" instead of "(Inherited from Object.)")
You have to write your own Equals method and compare the needed properties where. The built in (default) Contains() method will check values for value types (string, int...) and references for reference types (your class is a reference type)

Cast object into appropriate type for overloaded methods

Say I have a method that is overloaded such as void PrintInfo(Person) and void PrintInfo(Item), and so on. I try to invoke these methods by passing in an Object.
I'm wondering why it is giving me an error when I do this; aren't all classes inherited from Object? I want to avoid doing an if/switch statement where I check which type the Object is before calling the appropriate method.
What do you guys think is the best approach in this case?
All Persons are objects , but not all objects are Persons. Because of this you can pass a Person to a method that accepts an object but you can't pass an object to a method that requires a Person.
It sounds like you have some common bit of functionality between various objects that you want to use. Given this, it would be best to find either a common ancestor that has all of the functionality that you need, or an interface that they all implement (that again provides everything that you need).
In the case of printing, you may just need the ToString method. In that case, you can just have the method accept an object and call ToString on it. (That's what many print methods do, such as Console.WriteLine.
You need to understand that because C# is a statically typed language (barring dynamic) the particular overload that is chosen (called overload resolution) is determined at compile time, not run time. That means that the compiler needs to be able to unequivocally determine what type your argument is. Consider:
Object foo;
foo = "String";
foo = 5;
PrintInfo(foo); // Which overload of printinfo should be called? The compiler doesn't know!
There are a few ways to solve this- making foo of type dynamic is one- that will cause the correct overload to be chosen at compile time. The problem with that is that you lose type safety- if you don't have an appropriate overload for that type, your application will still compile but will crash when you try to print the unsupported type's info.
An arguably better approach is to ensure that foo is always of the correct type, rather than just Object.
As #Servy suggests, another approach is to attach the behavior to the type itself. You could, for instance, make an interface IHasPrintInfo:
public interface IHasPrintInfo { String PrintInfo { get; } }
and implement that interface on all items whose info you might print. Then your PrintInfo function can just take an IPrintInfo:
public void PrintInfo(IPrintInfo info) {
Console.WriteLine(info.PrintInfo);
}
here its ambiguate for compiler; compiler can't figure out which version of method (Person/Item) you are intended to call.

CollectionAssert.AreEqual Failing

I am trying to compare two Lists using
CollectionAssert.AreEqual(ListExpected, ListActual);
But I am getting an exception
Expected and actual are both <System.Collections.Generic.List`1[API.Program.Relation]> with 11 elements
Values differ at index [0]
Expected: <API.Program.Relation>
But was: <API.Program.Relation>
But when I compared the zero element using Assert.AreEqual on field by field everything was fine.
Any idea why I cannot compare using CollectionAssert
An object is "declared" equal to another object in .NET is if its Equals(object other) method returns true. You need to implement that method for your API.Program.Relation class, otherwise .NET considers your objects different unless they are reference-equal. The fact that all fields are the same does not matter to .NET: if you need field-by-field equality semantics, you need to provide an implementation of Equals that supports it.
When you override Equals, don't forget to override GetHashCode as well - these must be overriden together.
If you do not want to or cannot override Equals for some reason, you could use an overload of CollectionAssert.AreEqual that takes an instance of IComparer to assist in comparing collection elements.

When can a == b be false and a.Equals(b) true?

I ran into this situation today. I have an object which I'm testing for equality; the Create() method returns a subclass implementation of MyObject.
MyObject a = MyObject.Create();
MyObject b = MyObject.Create();
a == b; // is false
a.Equals(b); // is true
Note I have also over-ridden Equals() in the subclass implementation, which does a very basic check to see whether or not the passed-in object is null and is of the subclass's type. If both those conditions are met, the objects are deemed to be equal.
The other slightly odd thing is that my unit test suite does some tests similar to
Assert.AreEqual(MyObject.Create(), MyObject.Create()); // Green bar
and the expected result is observed. Therefore I guess that NUnit uses a.Equals(b) under the covers, rather than a == b as I had assumed.
Side note: I program in a mixture of .NET and Java, so I might be mixing up my expectations/assumptions here. I thought, however, that a == b worked more consistently in .NET than it did in Java where you often have to use equals() to test equality.
UPDATE Here's the implementation of Equals(), as requested:
public override bool Equals(object obj) {
return obj != null && obj is MyObjectSubclass;
}
The key difference between == and Equals is that == (like all operators) is not polymorphic, while Equals (like any virtual function) is.
By default, reference types will get identical results for == and Equals, because they both compare references. It's also certainly possible to code your operator logic and Equals logic entirely differently, though that seems nonsensical to do. The biggest gotcha comes when using the == (or any) operator at a higher level than the desired logic is declared (in other words, referencing the object as a parent class that either doesn't explicitly define the operator or defines it differently than the true class). In such cases the logic for the class that it's referenced as is used for operators, but the logic for Equals comes from whatever class the object actually is.
I want to state emphatically that, based solely upon the information in your question, there is absolutely no reason to think or assume that Equals compares values versus references. It's trivially easy to create such a class, but this is not a language specification.
Post-question-edit edit
Your implementation of Equals will return true for any non-null instance of your class. Though the syntax makes me think that you aren't, you may be confusing the is C# keyword (which confirms type) with the is keyword in VB.NET (which confirms referential equality). If that is indeed the case, then you can make an explicit reference comparison in C# by using Object.ReferenceEquals(this, obj).
In any case, this is why you are seeing true for Equals, since you're passing in a non-null instance of your class.
Incidentally, your comment about NUnit using Equals is true for the same reason; because operators are not polymorphic, there would be no way for a particular class to define custom equality behavior if the Assert function used ==.
a == b checks if they reference the same object.
a.Equals(b) compares the contents.
This is a link to a Jon Skeet article from 2004 that explains it better.
You pretty much answered your question yourself:
I have also over-ridden Equals() in the subclass implementation, which does a very basic check to see whether or not the passed-in object is null and is of the subclass's type. If both those conditions are met, the objects are deemed to be equal.
The == operator hasn't been overloaded - so it's returning false since a and b are different objects. But a.Equals is calling your override, which is presumably returning true because neither a nor b are null, and they're both of the subclass' type.
So your question was "When can a == b be false and a.Equals(b) true?" Your answer in this case is: when you explicitly code it to be so!
In Java a ==b check if the references of the two objects are equals (rougly, if the two objects are the same object "aliased")
a.equals(b) compare the values represented by the two objects.
They both do the same unless they are specifically overloaded within the object to do something else.
A quote from the Jon Skeet Article mentioned elsewhere.
The Equals method is just a virtual
one defined in System.Object, and
overridden by whichever classes choose
to do so. The == operator is an
operator which can be overloaded by
classes, but which usually has
identity behaviour.
The keyword here is USUALLY. They can be written to do whatever the underlying class wishes and in no way do they have to do the same.
The "==" operate tests absolute equality (unless overloaded); that is, it tests whether two objects are the same object. That's only true if you assigned one to the other, ie.
MyObject a = MyObject.Create();
MyObject b = a;
Just setting all the properties of two objects equal doesn't mean the objects themselves are. Under the hood, what the "==" operator is comparing is the addresses of the objects in memory. A practical effect of this is that if two objects are truly equal, changing a property on one of them will also change it on the other, whereas if they're only similar ("Equals" equal), it won't. This is perfectly consistent once you understand the principle.
I believe that a == b will check if the referenced object is the same.
Usually to see if the value is the same a.Equals(b) is used (this often needs to be overridden in order to work).

Using LINQ's Except<> method with an object from an external API

I have a List<> of HTMLAnchor objects (HTMLAnchor is an object from an external API). I want to exclude clicking on some of the links as they are for logging out, etc.
Using LINQ, I can use the Except operator. However, on here (http://msdn.microsoft.com/en-us/vcsharp/aa336761.aspx#except1), the example using the custom type (Product if I remember correctly) does not use the overloaded version of Except.
Furthermore, if I am using a type not defined by me, do the rules change? And should the class I write to implement IEquality have the same name I am trying to exclude in my generic collection (HtmlAnchor)?
Thanks
If you want to compare anchors using the default Equals method, which in this case will probably give you reference equality, you don't need to do anything: just pass the set of anchors to exclude:
anchors.Except(anchorsToExclude);
If the members of the sequence to exclude will not be reference-equal (or whatever HtmlAnchor.Equals deems equal), the interface you want to implement is IEqualityComparer<T>. This exists precisely to allow you to provide a custom equality comparison for a type that you don't define, so the rules don't change -- you just have to use the appropriate overload of Except.
So you would create a class called e.g. HtmlAnchorEqualityComparer which implements IEqualityComparer<HtmlAnchor>, and pass an instance of that to Except:
anchors.Except(anchorsToExclude, new HtmlAnchorEqualityComparer())
When you don't have control over the type, and the default equality operations do not suffice (ie. Equals is not properly implemented), you should use the overload which takes an IEqualityComparer<T> parameter. This is a class that you can implement yourself to provide the definition of equality, that you need.

Categories

Resources