Recently I was trying to write a unit test testing to see if one object was equal to another. The objects themselves were simple, just a collection of built-in types, so it should be easy to test.
public class SimpleObject | |
{ | |
public string Name { get; set; } | |
public int Id { get; set; } | |
} | |
public class SimpleTest | |
{ | |
[Fact(DisplayName = "Simple objects should be the same!")] | |
public void SimpleObject_AreEqual() | |
{ | |
SimpleObject obj1 = new SimpleObject | |
{ | |
Name = "George", | |
Id = 42 | |
}; | |
SimpleObject obj2 = new SimpleObject | |
{ | |
Name = "George", | |
Id = 42 | |
}; | |
// This will fail! | |
Assert.Equal(obj1, obj2); | |
} | |
} |
.Equals
However, since I didn’t implement .Equals, C# doesn’t natively know how to check if the objects are equal. This isn’t a bad thing – C# just wants you to define what makes an instance of an object ‘equal’ to another one.
Message: Assert.Equal() Failure
Expected: SimpleObject { Id = 42, Name = “George” }
Actual: SimpleObject { Id = 42, Name = “George” }
For my case, I just wanted to check each public property and see if they are the same values on both instances.
Enter Reflection
Rather than write a function to check each property individually (like you probably would do in a .Equals implementation), Reflection (also known as black magic, voodoo, or pixie dust) can loop over the public properties and check them for us.
I added this to my testing base class so that I can just easily pass two objects to it and have it do all the assertions for me.
/// <summary> | |
/// Loops through the public properties of the provided objects to see if they're equal | |
/// </summary> | |
/// <typeparam name="T">The type of objects to loop through</typeparam> | |
/// <param name="object1">The first object to check</param> | |
/// <param name="object2">The second object to check</param> | |
protected void AssertEquals<T>(T object1, T object2) where T: class | |
{ | |
if (object1 == null && object2 == null) return; | |
Assert.NotNull(object1); | |
Assert.NotNull(object2); | |
// Find the Public Instance properties | |
foreach (var prop in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)) | |
{ | |
// Get each object's value for the property | |
var value1 = prop.GetValue(object1); | |
var value2 = prop.GetValue(object2); | |
// If the property is a class, recursively call this method | |
// to check its properties, too. | |
if (prop.PropertyType.IsClass) | |
{ | |
Equals(value1, value2); | |
continue; | |
} | |
// Check the values of the properties against eachother | |
Assert.Equal(value1, value2); | |
} | |
} |
Disclaimer: I haven’t written unit tests specifically against this to check to make sure it works in all cases, so I’m not guaranteeing anything. It was just something I wrote up quick and thought it would be useful for myself in the future, so I documented it here. I tried to put a couple safeguards for the low-hanging fruit in there, but, ultimately, the code is provided here with no warranty.