我正在使用 FluentAssertions 比较两个使用 Should().BeEquivalentTo()
的对象,其中一个对象是 EF 动态代理。但是,似乎 5.0.0 中 ShouldBeEquivalentTo
和 ShouldAllBeEquivalentTo
( #593 ) 的统一在使用 RespectingRuntimeTypes
时破坏了功能。除非我为对象图中的每个类型显式添加 ComparingByMembers
,否则不再比较已声明类型的派生类型的属性成员。使用其他设置有什么办法解决这个问题吗?
最佳答案
我已经编写了以下扩展方法来尝试解决该问题,但仅在运行时在动态代理上修复派生类型的问题似乎很麻烦:
public static class FluentAssertionsExtensions
{
/// <summary>
/// Extends the functionality of <see cref="EquivalencyAssertionOptions{TExpectation}" />.ComparingByMembers by recursing into the entire object graph
/// of the T or passed object and marks all property reference types as types that should be compared by its members even though it may override the
/// System.Object.Equals(System.Object) method. T should be used in conjunction with RespectingDeclaredTypes. The passed object should be used in
/// conjunction with RespectingRuntimeTypes.
/// </summary>
public static EquivalencyAssertionOptions<T> ComparingByMembersRecursive<T>(this EquivalencyAssertionOptions<T> options, object obj = null)
{
var handledTypes = new HashSet<Type>();
var items = new Stack<(object obj, Type type)>(new[] { (obj, obj?.GetType() ?? typeof(T)) });
while (items.Any())
{
(object obj, Type type) item = items.Pop();
Type type = item.obj?.GetType() ?? item.type;
if (!handledTypes.Contains(type))
{
handledTypes.Add(type);
foreach (PropertyInfo pi in type.GetProperties())
{
object nextObject = item.obj != null ? pi.GetValue(item.obj) : null;
Type nextType = nextObject?.GetType() ?? pi.PropertyType;
// Skip string as it is essentially an array of chars, and needn't be processed.
if (nextType != typeof(string))
{
if (nextType.GetInterface(nameof(IEnumerable)) != null)
{
nextType = nextType.HasElementType ? nextType.GetElementType() : nextType.GetGenericArguments().First();
if (nextObject != null)
{
// Look at all objects in a collection in case any derive from the collection element type.
foreach (object enumObj in (IEnumerable)nextObject)
{
items.Push((enumObj, nextType));
}
continue;
}
}
items.Push((nextObject, nextType));
}
}
if (type.IsClass && type != typeof(string))
{
// ReSharper disable once PossibleNullReferenceException
options = (EquivalencyAssertionOptions<T>)options
.GetType()
.GetMethod(nameof(EquivalencyAssertionOptions<T>.ComparingByMembers))
.MakeGenericMethod(type).Invoke(options, null);
}
}
}
return options;
}
}
应该这样称呼:
foo.Should().BeEquivalentTo(bar, o => o
.RespectingRuntimeTypes()
.ComparingByMembersRecursive(foo)
.ExcludingMissingMembers());
关于c# - FluentAssertions Should().BeEquivalentTo 不比较 EF 动态代理上的运行时派生类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49327679/