You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FluentAssertions的ExcludingNestedObjects选项行为不符预期的技术咨询

FluentAssertions中ExcludingNestedObjects方法的疑问与解决

问题场景

先看这段C#代码:

class Parent
{
    public int Id { get; set; }
    public Child Child { get; set; }
}

class Child
{
    public int Id { get; set; }
}

var p1 = new Parent { Id = 0, Child = new Child { Id = 1 } };
var p2 = new Parent { Id = 0, Child = new Child { Id = 2 } };

p1.Should().BeEquivalentTo(p2);

如预期,断言失败,提示:

Expected property p1.Child.Id to be 2, but found 1.

把断言改成带ExcludingNestedObjects()的版本:

p1.Should().BeEquivalentTo(p2, o => o.ExcludingNestedObjects());

结果断言还是失败,提示:

Expected property p1.Child to be Child
{
Id = 2
}, but found Child
{
Id = 1
}

按照方法的帮助文本,ExcludingNestedObjects()应该让结构相等检查排除嵌套集合和复杂类型,但Child作为复杂类型还是被检查了,这是为什么?

目前能让断言通过的方式是逐个排除复杂类型属性:

p1.Should().BeEquivalentTo(p2, o => o.Excluding(p => p.Child));

但如果有大量复杂类型属性,逐个排除太麻烦。

原因解析

ExcludingNestedObjects()的实际作用和帮助文本的描述有偏差,它不会完全跳过复杂类型属性的检查,而是改变了检查逻辑:

  • 原本会递归检查嵌套对象的所有内部属性
  • 启用该方法后,停止递归检查,转而使用对象的默认相等规则来判断这个嵌套对象本身是否相等

对于自定义的Child类,因为没有重写Equals和GetHashCode方法,默认会用引用相等性来比较。p1.Child和p2.Child是两个不同的实例,引用地址不一样,所以断言判定它们不相等,导致失败。

批量排除复杂类型的解决方案

如果要批量排除所有自定义复杂类型的属性,可以通过筛选规则实现,不用逐个指定属性:

p1.Should().BeEquivalentTo(p2, options => options
    .Excluding(ctx => !ctx.SelectedMemberInfo.PropertyType.IsValueType 
                      && !ctx.SelectedMemberInfo.PropertyType.Equals(typeof(string))));

这个规则会排除所有非值类型且非字符串的属性,也就是所有自定义的复杂类对象,一次性解决批量排除的需求。

如果需要更灵活的比较逻辑,还可以自定义IEquivalencyStep来扩展,但上述方式已经能覆盖大部分场景。

内容的提问来源于stack exchange,提问作者Andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 18:40:27