15

I have two objects in my unit test, the actual and expected object. All properties on the object method are the exact same and if I run the following test:

Assert.AreEqual( expectedObject.Property1, actualObject.Property1);

the result passes as expected. However, when I try to run the following test it fails:

Assert.AreEqual (expectedObject, actualObject);

What am I missing? Can two objects not be compared and do I have to do a check on each property?

Blake Blackwell
  • 7,575
  • 10
  • 50
  • 67
  • 2
    Here's a similar question for NUnit that will be helpful: http://stackoverflow.com/questions/318210/compare-equality-between-two-objects-in-nunit – Chris Van Opstal Feb 05 '10 at 14:23
  • for actually performing the work you'd like to I wrote a utility class that compares the two object's properties by using reflection. At the moment I don't have the code at hand, but it's not difficult to implement such a functionality. – Juri Feb 05 '10 at 14:25
  • If you come upon that code Juri, I would love to see what you've done. – Blake Blackwell Feb 05 '10 at 14:29

8 Answers8

17

You need to override Equals for your object. Assert uses Object.Equals. By default, Object.Equals on objects of reference type performs a reference comparison. That is, two instances of a reference type are equal if and only if they refer to the same object. You want to override this so that instead of a reference comparison being performed a value comparison is performed. Here is a very nice MSDN article on the subject. Note that you also need to override GetHashCode. See MSDN fo the guidelines. Here is a simple example:

Before:

class Test {
    public int Value { get; set; }
}

Test first = new Test { Value = 17 };
Test second = new Test { Value = 17 };
Console.WriteLine(first.Equals(second)); // false

After:

class Test {
    public int Value { get; set; }
    public override bool Equals(object obj) {
        Test other = obj as Test;
        if(other == null) {
            return false; 
        }
        return this.Value == other.Value;
    }
    public override int GetHashCode() { 
        return this.Value.GetHashCode();
    }
}

Test first = new Test { Value = 17 };
Test second = new Test { Value = 17 };
Console.WriteLine(first.Equals(second)); // true
jason
  • 236,483
  • 35
  • 423
  • 525
  • 3
    Watch out for Equality Pollution. Overriding Equals may not be the correct thing to do. See here for more information: http://stackoverflow.com/questions/2046121/how-to-compare-two-object-in-unit-test-how-to-compare-two-collection-in-unit-tes/2047576#2047576 – Mark Seemann Feb 05 '10 at 15:23
4

The second assert statement actually compares the references of the objects, not the content. Since the parameters of the AreEqual method are of type objects, there's not much information on how the unit test framework should compare these.

EDIT: check this question: Compare equality between two objects in NUnit

Community
  • 1
  • 1
Gerrie Schenck
  • 22,148
  • 20
  • 68
  • 95
1

You could not use the '= ' sign unless you have overloaded it to your object. In your object class you need to do something like:


public override bool Equals(object obj)
{
   if(obj == null)
      return false;
   return (this.Property1 == obj.Property1 && 
          this.Property2 == obj.Property2);
}

If you don't do this, then you are just simply comparing the object references.

Freddy
  • 3,064
  • 3
  • 26
  • 27
1

This is true. Whether the two objects are equal or not are entirely depends on its Equals method's implementation. Sometime with the Equal method, it is also good to override the GetHashCode implementation. If it is not override, the default virtual implementation (of Object class) would be considered along with the the Equal method's evaluation. For object to be considered equal their hash code should be the same.

However for the unit test, I would suggest don't rely heavily on Equal method's implementation. Whatever Property you want to ascertain compare those properties of the object by yourself because again the Equal method could be the custom implementation so there are possibility it might contain errors at the end of the day. So better trust upon the system defined class's Equal method for unit testing.

0

https://github.com/kbilsted/StatePrinter has been written specifically to dump object graphs to string representation with the aim of writing easy unit tests.

  • It comes witg Assert methods that output a properly escaped string easy copy-paste into the test to correct it.
  • It allows unittest to be automatically re-written
  • It integrates with all unit testing frameworks
  • Unlike JSON serialization, circular references are supported
  • You can easily filter, so only parts of types are dumped

Given

class A
{
  public DateTime X;
  public DateTime Y { get; set; }
  public string Name;
}

You can in a type safe manner, and using auto-completion of visual studio include or exclude fields.

  var printer = new Stateprinter();
  printer.Configuration.Projectionharvester().Exclude<A>(x => x.X, x => x.Y);

  var sut = new A { X = DateTime.Now, Name = "Charly" };

  var expected = @"new A(){ Name = ""Charly""}";
  printer.Assert.PrintIsSame(expected, sut);
Carlo V. Dango
  • 13,322
  • 16
  • 71
  • 114
0

That's typical equivalence problem and looks like accepted answer is not a good one. I'll try to explain why.

Imagine the following - you have to write integration test on your backend to assure it stores your domain object correcty. You have a code:

[TestMethod]
    [Description(@"Sequentially perform operations
                 1. Save new item in DB
                 2. Get same Item from DB
                 Ensure that saved and get Items are equivalent")]
    public void Repository_Create_Test()
    {
        var initialItem = GetTestItem();
        //create item and check it is created correct
        initialItem.ID = repository.Create(initialItem, userID, ownerID);
        Item resultItem = repository.GetById(initialItem.ID, ownerID);
        resultItem.Should().NotBeNull();
        Assert.AreEqual(initialItem, resultItem);
    }

So, you need to verify that the object read from storage is absolute equivalent of the object that we've send to the storage. Overriding Equals is an easy first guess here. For this case we need to setup Equals to compare all objects fields. But from DDD perspective thats just plain wrong. Domain Entities are distinguished by immutable key (or primary key) and not by all the mutable fields. So, if we are modelling HR domain and hypothetical 'Mister X' has a new phone number, he still remains the very same 'Mister X'.

All that said, I've currently using FluentAssertions Framework that has rather powerful facility for equivalence check. Like this:

resultItem.ShouldBeEquivalentTo(initialItem);
Konstantin Chernov
  • 1,899
  • 2
  • 21
  • 37
0

I know this is an old question, but as I was reading through the answers I thought of an easy hack. Maybe others already know this hack, but since it isn't mentioned here...

I already have Newtonsoft.Json as part of my project. So I can easily use the JsonConvert.SerializeObject(obj) on both the expected and actual. Then it is just Assert.AreEqual for two strings.

Worked for me :)

ajr
  • 73
  • 1
  • 9
0

Deepak : That means at the end of the day I will not compare the objects. Compare the Objects Properties Value. Correct..This equal override method is only for particular Object...This is limitation not a correct way...

Here Is good Link...Before Prepare UnitTest make your own class for Testing Help

http://manfred-ramoser.blogspot.com/2007/11/c-unit-testing-helper.html

Saroop Trivedi
  • 2,245
  • 6
  • 31
  • 49