Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Compare all fields of objects in NUnit
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Helpers
{
/// <summary>
/// Factory that creates an equality comparer that checks if all properties are equal (using == operator)
/// Consider using <see cref="AllFieldsEqualityComprision"/> if type is unknown at compile time
/// </summary>
public static class AllFieldsEqualityComprision<T>
{
private class DelegateEqualityComparer : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _equalFunc;
public DelegateEqualityComparer(Func<T, T, bool> equalFunc)
{
_equalFunc = equalFunc;
}
public bool Equals(T x, T y) => _equalFunc(x, y);
public int GetHashCode(T obj) => 0;
}
public static IEqualityComparer<T> Instance { get; } = GetInstance();
private static IEqualityComparer<T> GetInstance()
{
var type = typeof(T);
ParameterExpression[] parameters =
{
Expression.Parameter(type, "x"),
Expression.Parameter(type, "y")
};
var result = type.GetProperties().Aggregate<PropertyInfo, Expression>(
Expression.Constant(true),
(acc, prop) =>
Expression.And(acc,
Expression.Equal(
Expression.Property(parameters[0], prop.Name),
Expression.Property(parameters[1], prop.Name))));
var expr = Expression.Lambda<Func<T, T, bool>>(result, parameters);
var equalFunc = expr.Compile();
return new DelegateEqualityComparer(equalFunc);
}
}
/// <summary>
/// Class that creates an equality comparer that checks if all properties are equal (using == operator)
/// Consider using <see cref="AllFieldsEqualityComprision{T}"/> if type is known at compile time
/// </summary>
public static class AllFieldsEqualityComprision
{
private class DelegateEqualityComparer : IEqualityComparer
{
private readonly Func<object, object, bool> _equalFunc;
public DelegateEqualityComparer(Func<object, object, bool> equalFunc)
{
_equalFunc = equalFunc;
}
bool IEqualityComparer.Equals(object x, object y) => _equalFunc(x,y);
public int GetHashCode(object obj) => 0;
}
public static IEqualityComparer GetInstance(Type type)
{
ParameterExpression[] parameters =
{
Expression.Parameter(typeof(object), "x"),
Expression.Parameter(typeof(object), "y")
};
var castedX = Expression.Variable(type);
var castedY = Expression.Variable(type);
var result = type.GetProperties().Aggregate<PropertyInfo, Expression>(Expression.Constant(true),
(acc, prop) => Expression.And(acc,
Expression.Equal(Expression.Property(castedX, prop.Name), Expression.Property(castedY, prop.Name))));
var expr = Expression.Lambda<Func<object, object, bool>>(Expression.Block(new[] {castedX, castedY},
Expression.Assign(castedX, Expression.Convert(parameters[0], type)),
Expression.Assign(castedY, Expression.Convert(parameters[1], type)),
result), parameters);
var equalFunc = expr.Compile();
return new DelegateEqualityComparer(equalFunc);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using ExpectedObjects;
using NUnit.Framework;
namespace Helpers
{
public static class AssertEx
{
public static void AllPropertiesAreEquals<T>(T expected, T actual)
{
foreach (var property in typeof(T).GetProperties())
{
var expectedVal = property.GetValue(expected);
var actualVal = property.GetValue(actual);
try
{
Assert.AreEqual(expectedVal, actualVal);
}
catch
{
var type = property.PropertyType.IsGenericType && property.PropertyType.GetInterface(nameof(IEnumerable)) != null
? property.PropertyType.GenericTypeArguments[0]
: property.PropertyType;
Assert.That(actualVal,
Is.EqualTo(expectedVal).Using(AllFieldsEqualityComprision.GetInstance(type)), $"Property {property.Name}");
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment