fredag, januari 26, 2007

Compare objects in unit test

Today I wanted to create some unit tests for a object relationship mapper that Connecta developed for a client. The method I wanted to test was a find method that takes an id for an entity and returns that entity from the database. The entity that I searched for was created in a static method marked with the [ClassInitialize()] attribute.

By the way, I use Team System for unit testing.

So, how do I compare the objected that I created with the object that I got from the database? Will I be happy with just comparing what ToString returns or do I take a random number of properties and compare them? No, the only reasonable thing to do is to compare the value of every property on the objects.

To do this I created a new static class in my test project called
ObjectComparer
. ObjectComparer has one method called CompareObjects that takes the two objects to compare as in-parameters. Then I use reflection to find the properties on the object and compare the value of every property in the two objects. That worked really well but I soon realized that I needed a way to exclude properties from the compare method. For instance there can be a datetime field that holds a datetime for when the record was created in the database. This field will never be the same in a compare and therefore needs to be ignored. So I added another parameter that will hold a generic list that contains the names of the properties to ignore: List<string> IgnoreList.
CompareObjects returns another object called ObjectCompareResult that contains two properties, a Boolean containing the result of the compare and a string containing the possible error message if the compare returns false.

Here is the code for the method CompareObjects:

public static ObjectCompareResult CompareObjects(object obj1, object obj2, List<string> IgnoreList)
{
Type objectType1 = obj1.GetType();
PropertyInfo[] propertyInfos = objectType1.GetProperties();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (IgnoreList == null || (IgnoreList != null && !IgnoreList.Contains(propertyInfo.Name.ToString())))
if (!propertyInfo.GetValue(obj1, null).Equals(propertyInfo.GetValue(obj2, null)))
return new ObjectCompareResult(false, String.Format("The value of the property '{0}' is not the same in the two objects. Value from obj1 = '{1}'. Value from obj2 = '{2}'",
propertyInfo.Name.ToString(),
propertyInfo.GetValue(obj1, null),
propertyInfo.GetValue(obj2, null)));
}
return new ObjectCompareResult(true);
}



And here is the code for the unit test:

[TestMethod()]
public void FindTest()
{
MyStorage target = FrameworkUnitTest.Framework_Storage_MyStorageAccessor.CreatePrivate();
MyEntity expected = myEntity; //Created in the ClassInitialize
MyEntity actual = target.Find(myId);
List ignoreList = new List();
ignoreList.Add("DateCreated");

ObjectCompareResult result = ObjectComparer.CompareObjects(expected, actual);

Assert.IsTrue(result.CompareResult, result.CompareMessage);
}


Thanks to my peers for help when it comes to reflection and comparing object values!