FluentAssertions Should().BeeEquivalentto()在一个简单的情况下失败,当类型是C#9记录时,似乎将对象视为字符串

FluentAssertions Should().BeeEquivalentto()在一个简单的情况下失败,当类型是C#9记录时,似乎将对象视为字符串,c#,.net-5,fluent-assertions,C#,.net 5,Fluent Assertions,我最近开始使用FluentAssertions,它应该有这个强大的对象图比较功能 我正在尝试做一件最简单的事情:将地址对象的属性与地址到对象的属性进行比较。它们都包含4个简单的字符串属性:Country、City、Street和ZipCode(它不是生产系统) 有没有人能像我两岁那样向我解释一下,出了什么问题 partnerDto.Address.Should().BeEquivalentTo(partner.Address) 它将失败,并显示以下消息: 信息: 预期结果。地址为加拿大多伦多1

我最近开始使用FluentAssertions,它应该有这个强大的对象图比较功能

我正在尝试做一件最简单的事情:将
地址
对象的属性与
地址到
对象的属性进行比较。它们都包含4个简单的字符串属性:Country、City、Street和ZipCode(它不是生产系统)

有没有人能像我两岁那样向我解释一下,出了什么问题

partnerDto.Address.Should().BeEquivalentTo(partner.Address)
它将失败,并显示以下消息:

信息:

预期结果。地址为加拿大多伦多12345号Some street 4号, 但找到的地址是{Country=Canada,ZipCode=12345,City=Toronto,Street=4 Some Street}

配置:

  • 使用声明的类型和成员
  • 按值比较枚举
  • 按名称匹配成员(或抛出)
  • 没有自动转换
  • 严格控制字节数组中项目的顺序
它似乎试图将
地址
对象视为字符串(因为它重写了
ToString()
?)。我尝试使用
选项.ComparingByMembers

我确认如果我将
记录
更改为
,则不会出现问题

(我个人认为FluentAssertions在
记录上时应该忽略Equals()覆盖,这两种类型是不同的,因为这种行为可能不是人们所期望的。在发布时,当前的问题与FluentAssertions版本5.10.3有关)

我编辑了我的问题标题,以更好地反映问题的实际情况,因此它对人们更有用


参考文献:

正如人们所问,这里是域实体的定义(为了简洁起见,我不得不删除一些方法,因为我在做DDD,但它们肯定与问题无关):

公共类合作伙伴:MyEntity
{
[必需]
[StringLength(PartnerInvariants.NameMaxLength)]
公共字符串名称{get;private set;}
[必需]
公共地址{get;private set;}
公共虚拟IReadOnlyCollection事务=>_Transactions.AsReadOnly();
私有列表_事务=新列表();
私人合伙人()
{ }
公共合作伙伴(字符串名称、地址)
{
UpdateName(名称);
更新地址(地址);
}
...
公共void UpdateName(字符串值)
{
...
}
公共无效更新地址(地址)
{
...
}
...
}
公共记录地址
{
[必需,最小长度(1),最大长度(100)]
公共字符串Street{get;init;}
[必需,最小长度(1),最大长度(100)]
公共字符串城市{get;init;}
//正如我提到的,它不是一个生产系统:)
[必需,最小长度(1),最大长度(100)]
公共字符串国家{get;init;}
[必需,最小长度(1),最大长度(100)]
公共字符串ZipCode{get;init;}
专用地址(){}
公共广播(字符串街道、字符串城市、字符串国家、字符串zipcode)
=>(街道、城市、国家、邮编)=(街道、城市、国家、邮编);
公共重写字符串ToString()
=>$“{Street},{ZipCode}{City},{Country}”;
}
以下是Dto的等价物:

公共记录PartnerDetailsTo:IMapFrom
{
公共int Id{get;init;}
公共字符串名称{get;init;}
public DateTime CreatedAt{get;init;}
公共日期时间?LastModifiedAt{get;init;}
公共地址到地址{get;init;}
公共空白映射(配置文件)
{
CreateMap();
CreateMap();
}
公共记录地址
{
公共字符串国家{get;init;}
公共字符串ZipCode{get;init;}
公共字符串城市{get;init;}
公共字符串Street{get;init;}
}
}

您是否尝试过使用
选项。ComparingByMembers()


尝试将测试更改为:
partnerDto.Address.Should().beequivalento(partner.Address,o=>o.ComparingByMembers())

我认为这本书的重要部分是:

要确定Fluent断言是否应该递归到对象的属性或字段中,需要了解哪些类型具有值语义,哪些类型应该被视为引用类型。默认行为是将重写Object.Equals的每个类型视为具有值语义的对象

这两条记录都覆盖了
Equals
,但它们的Equals方法只有在另一个对象的类型相同时才会返回true。因此我认为,
Should().beequivalento
就是看到您的对象实现了它们自己的相等,调用(大概是)
AddressDto.Equals,返回false,然后报告失败

它使用两条记录的
ToString()
版本报告失败,这两条记录返回
{Country=Canada,ZipCode=12345,City=Toronto,Street=4 Some Street}
(对于没有重写ToString的记录)和
4 Some Street,12345 Toronto,Canada,
(对于具有重写ToString的对象)

正如文档所说,您应该能够通过使用
ComparingByMembers
来覆盖这一点:

partnerDto.Address.Should().BeEquivalentTo(partner.Address,
   options => options.ComparingByMembers<Address>());
partnerDto.Address.Should().BeEquivalentTo(partner.Address,
options=>options.ComparingByMembers());
或全球:

AssertionOptions.AssertEquivalencyUsing(options => options
    .ComparingByMembers<Address>());
AssertionOptions.AssertEquivalencyUsing(选项=>options
.ComparingByMembers());

你能把问题包括在
地址和
地址的定义中吗;稍等一下,
partnerDto
变量的类型是什么?如何定义
地址
属性?@Leak