3

I have a class which contains this attributes:

public class Person
{
    public long Id { get; set; }

    public string Name { get; set; }

    public int? IdCountry { get; set; }
    public virtual Country Country { get; set; }
    public int? IdState { get; set; }
    public virtual State State { get; set; }
}

public class Country
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class State
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int IdCountry { get; set; }
    public virtual Country Country { get; set; }
}

In a unit test I create 2 objects with the same values

Person expected = new Person()
{
    Name = "blablablbla",
    Id = 1
};
Person actual = PessoaFactory.Create(Name: "blablablbla", Id: 1);
Assert.AreEqual<Person>(expected, actual);

But the Assert.AreEqual throws an exception.

  • 3
    Because Object.Equals() (what will be finally called) will **compare references** (you have classes, not structs) and obviously they're two different objects (two instances). **Override it** if you want to implement some sort of comparison between Person (**what kind of comparison**...well it depends. ID only? All fields? Up to you). – Adriano Repetti Nov 19 '13 at 13:33

5 Answers5

6

You need to override Equals to compare the objects. The default implementation compares references, not values. See the MSDN documentation.

Patrick Quirk
  • 23,334
  • 2
  • 57
  • 88
3

Because you need to override Equals and GetHashCode:

public override bool Equals(object o)
{
    if (!(o is Person)) { return false; }
    return ((Person)o).Id == this.Id;
}

public override int GetHashCode()
{
    return this.Id;
}

Assert.AreEqual<T> uses the default comparer for the type. The default comparer for that type is to compare hash codes. The hash codes aren't equal.

Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
  • 2
    ...and `GetHashCode()`. We preach best practice where possible. – Gusdor Nov 19 '13 at 13:33
  • You will need to override `GetHashCode()` as well – Rui Jarimba Nov 19 '13 at 13:34
  • @RuiJarimba, you actually don't **have** to `override` the `GetHashCode` method; but it's a good practice so I modified as such. But let's be clear, it does not **have** to be done. – Mike Perrenoud Nov 19 '13 at 13:35
  • 1
    Just an FYI if the OP is comparing *multiple* properties and not just the ID these need to be taken into consideration in both checks - otherwise `new Person { Id = 1, Name = "Person1" }; new Person { Id = 1, Name = "Person2" }` would be equal (when the OP might not want them to be). – James Nov 19 '13 at 13:38
  • @James, fair enough; I just didn't want to write out every single property since it's not evident. – Mike Perrenoud Nov 19 '13 at 13:40
  • @MichaelPerrenoud: if you override one of those methods then you should override the other one. The alternative is to use an `IEqualityComparer`: http://stackoverflow.com/a/10807365/558486 – Rui Jarimba Nov 19 '13 at 13:44
  • @RuiJarimba, I didn't argue the practice; I argued the fact that you stated it was a **necessity.** The statement that it's a **necessity** is wrong. However, I fully agree with the practice and updated my answer to show; did I not? Second, `IEqualityComparer` won't work here because the base `Assert.AreEqual` calls `Equals`. – Mike Perrenoud Nov 19 '13 at 13:48
  • @MichaelPerrenoud: fair enough. Regarding the `IEqualityComparer` - see the link I added. – Rui Jarimba Nov 19 '13 at 13:51
  • 1
    @MichaelPerrenoud sure, plus the OP doesn't really mention whether it is just the ID they are comparing or whether it's a field-level comparison so thought it was worth clarifying. – James Nov 19 '13 at 14:51
2

Because it is comparing the references not the actual values within it.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
2

You have two different object references to compare.

Instead use Assert.IsTrue(expected.Id == actual.Id) for example or override Equals and GetHashCode to be able to compare your objects

MichaC
  • 13,104
  • 2
  • 44
  • 56
0

The .Net framework itself doesn't handle deep equality cooperation by default, Assert.AreEqual calls the Equals method on the object which is object.Equals if you didn't override the method. Object.Equals is implementing reference check only. You should implement your own Equals method, for example:

public override bool Equals(object o)
{
    var cast = o as Person;
    if (cast == null) 
        return false; 
    return cast.Id == this.Id;
}

public override int GetHashCode()
{
    return this.Id;
}

For more information you can check this MSDN Doc

Matan Shahar
  • 3,190
  • 2
  • 20
  • 45