Compare equality between two objects in NUnit
Solution 1:
Do not override Equals just for testing purposes. It's tedious and affects domain logic. Instead,
Use JSON to compare the object's data
No additional logic on your objects. No extra tasks for testing.
Just use this simple method:
public static void AreEqualByJson(object expected, object actual)
{
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var expectedJson = serializer.Serialize(expected);
var actualJson = serializer.Serialize(actual);
Assert.AreEqual(expectedJson, actualJson);
}
It seems to work out great. The test runner results info will show the JSON string comparison (the object graph) included so you see directly what's wrong.
Also note! If you have bigger complex objects and just want to compare parts of them you can (use LINQ for sequence data) create anonymous objects to use with above method.
public void SomeTest()
{
var expect = new { PropA = 12, PropB = 14 };
var sut = loc.Resolve<SomeSvc>();
var bigObjectResult = sut.Execute(); // This will return a big object with loads of properties
AssExt.AreEqualByJson(expect, new { bigObjectResult.PropA, bigObjectResult.PropB });
}
Solution 2:
If you can't override Equals for any reason, you can build a helper method that iterates through public properties by reflection and assert each property. Something like this:
public static class AssertEx
{
public static void PropertyValuesAreEquals(object actual, object expected)
{
PropertyInfo[] properties = expected.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
object expectedValue = property.GetValue(expected, null);
object actualValue = property.GetValue(actual, null);
if (actualValue is IList)
AssertListsAreEquals(property, (IList)actualValue, (IList)expectedValue);
else if (!Equals(expectedValue, actualValue))
Assert.Fail("Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);
}
}
private static void AssertListsAreEquals(PropertyInfo property, IList actualList, IList expectedList)
{
if (actualList.Count != expectedList.Count)
Assert.Fail("Property {0}.{1} does not match. Expected IList containing {2} elements but was IList containing {3} elements", property.PropertyType.Name, property.Name, expectedList.Count, actualList.Count);
for (int i = 0; i < actualList.Count; i++)
if (!Equals(actualList[i], expectedList[i]))
Assert.Fail("Property {0}.{1} does not match. Expected IList with element {1} equals to {2} but was IList with element {1} equals to {3}", property.PropertyType.Name, property.Name, expectedList[i], actualList[i]);
}
}
Solution 3:
Try FluentAssertions library:
dto.Should().BeEquivalentTo(customer)
It can also be installed using NuGet.
Solution 4:
Override .Equals for your object and in the unit test you can then simply do this:
Assert.AreEqual(LeftObject, RightObject);
Of course, this might mean you just move all the individual comparisons to the .Equals method, but it would allow you to reuse that implementation for multiple tests, and probably makes sense to have if objects should be able to compare themselves with siblings anyway.