views:

64

answers:

3

I'm sure I missing something simple here but I can't figure out why my NUnit object comparison test continues to fail.

I have a simple object:

 public virtual int Id { get; private set; }

    public virtual string Description { get; set; }

    public virtual string Address { get; set; }

    public virtual string Ports { get; set; }

    public virtual string Password { get; set; }        

    public virtual ServerGroup ServerGroup { get; set; }

I am persisting an instance of this object to my database and then fetching it out using NHibernate. My NUnit unit test compares the object saved to the object retrieved and compares them. I understand that AreSame() would fail as they are not the same reference to an object but I would expect that AreEqual() pass.

If I debug the test I can see that both objects appear to have the same values in these properties my test still fails. Can someone tell me why?

Thanks!

+2  A: 

You have to override Equals() method on your class. Otherwise NUnit will use the base implementation, which compares references (which is certainly not what you are after here)

Grzenio
A: 

You do need to override Equals as Grzenio suggests, but watch out for a subtle source of confusion that can occur with NHibernate. Specifically, when lazy loading is enabled, a type comparison test can fail. To illustrate, here is a piece of a well written Equals method:

    // override object.Equals
    public override bool Equals(object obj)
    {
        //       
        // See the full list of guidelines at
        //   http://go.microsoft.com/fwlink/?LinkID=85237  
        // and also the guidance for operator== at
        //   http://go.microsoft.com/fwlink/?LinkId=85238
        //

        if (GetType() != obj.GetType())
        {
            return false;
        }
        ....
    }

But when lazy loading is enabled, the way NHib works is to generate a proxy of the actual object (thereby deferring unnecessary database hits). If an equality check is made between one object that has been 'proxified' by NHib and another that hasn't been, it will fail because of the mismatch in Types. The solution (courtesy of the S#arp Architecture project, is to modify the type test to be something like this:

public override bool Equals(object obj) {
    ...
    if (GetType() != obj.GetTypeUnproxied())
    {
        return false;
    }
       ...
 }

protected virtual Type GetTypeUnproxied() { return GetType(); }

This effectively returns the type of the underlying object in all cases, even when the compareTo object is a NHib proxy.

An Equals method can be as tricky as it is important to get just right, so ideally you can factor that into some sort of Layer Supertype (Fowler). Lots of open source projects, including the S#arp one I mentioned earlier, provide examples of how to do this.

HTH,
Berryl

Berryl
+1  A: 

As suggested you need to override Equals. You do need to be aware of the side effects.

You should also override GetHashCode or you could end up with objects where .Equals will be true, but using your Id class as the key in a Dictionary the hash would not match resulting in multiple entries with "Equal" Ids.

Also, you would need to override the == and != operators to maintain consistent behavior.

Imagine the confusion if .Equals were true but == were false.

Dennis Burton