如何在 FluentAssertions 中使用方法
Posted
技术标签:
【中文标题】如何在 FluentAssertions 中使用方法【英文标题】:How to use the method When in FluentAssertions 【发布时间】:2020-09-16 01:32:09 【问题描述】:有时我必须断言两个列表具有相同的项目。使用流利的断言可以这样做:
class MyObject public string MyString get; set;
var o1 = new MyObject MyString = "1 "
list1.Add(o1);
var o2 = new MyObject MyString = "1"
list2.Add(o2);
list1.Should().BeEquivalentTo(list2)
但有时我希望以不同的方式比较特定属性,例如:
list1.Should().BeEquivalentTo(list2, options => options
.Using<string>(context => context.Subject.TrimEnd().Should().Be(context.Expectation))
.When<string>( ??????? ));
我试过了:
it => it.SelectedMemberInfo.Name == PropertyNameHere
但是 SelectedMemberInfo 可以为 null 并且当为 null 时会引发异常,我不知道我是否以正确的方式调用它。
更新 1:已尝试,但为空引用异常:
options => options
.Using<DateTime>(it => it.Subject.Should().BeCloseTo(DateTime.Now, TimeSpan.FromMinutes(1)))
.When(it =>
it != null
&& it.SelectedMemberInfo != null
&& it.SelectedMemberInfo.Name == nameof(Y.X)));
【问题讨论】:
你能提供一个Minimal Complete Example 你想要达到的目标吗? 您能具体说明我的问题中缺少什么吗?我觉得很容易理解 在这种情况下,我不清楚list1
和 list2
是。如果您提供完整的示例,我可以将其复制/粘贴到 IDE 中并运行。
已编辑问题
【参考方案1】:
要匹配MyString
属性,最常用的两种方法是按类型匹配或按路径匹配。
要按类型匹配MyString
,请使用WhenTypeIs<string>
。
[TestMethod]
public void MatchByType()
var o1 = new MyObject MyString = "1 " ;
var list1 = new[] o1 ;
var o2 = new MyObject MyString = "1" ;
var list2 = new[] o2 ;
list1.Should().BeEquivalentTo(list2, opt => opt
.Using<string>(ctx => ctx.Subject.TrimEnd().Should().Be(ctx.Expectation))
.WhenTypeIs<string>());
对于好奇的WhenTypeIs<TMemberType>
只是一个别名
When(info => info.RuntimeType.IsSameOrInherits(typeof(TMemberType))
要通过名称匹配MyString
,您可以使用When(e => e.SelectedMemberPath)
。
SelectedMemberPath
定义为
从根对象到当前对象的完整路径,用点分隔。
在这种情况下,根对象是MyObject
,所以SelectedMemberPath
将是"MyString"
。
所以可以写成:
[TestMethod]
public void MatchByName()
var o1 = new MyObject MyString = "1 " ;
var list1 = new[] o1 ;
var o2 = new MyObject MyString = "1" ;
var list2 = new[] o2 ;
list1.Should().BeEquivalentTo(list2, opt => opt
.Using<string>(ctx => ctx.Subject.TrimEnd().Should().Be(ctx.Expectation))
.When(e => e.SelectedMemberPath.EndsWith(nameof(MyObject.MyString))));
【讨论】:
【参考方案2】:这里的问题是您试图访问尚未实例化的对象中的成员。因为it.SelectedMemberInfo
是null
,所以没有成员Name
可以访问。 NullReferenceException
上的 .NET 文档对此有很好的解释。
https://docs.microsoft.com/en-us/dotnet/api/system.nullreferenceexception?view=netcore-3.1
假设SelectedMemberInfo
为空时没有其他特殊情况,您只想使.When()
中的表达式为空安全。您可以使用单个字符轻松完成此操作(空传播):
it => it.SelectedMemberInfo?.Name == PropertyNameHere
null 传播的工作方式是,如果问号前面的对象为 null,它将在语句末尾评估为该类型的 null 实例。所以在这种情况下,如果it.SelectedMemberInfo
为空,则计算结果为(string) null
。
如果你喜欢额外的线条,你也可以这样做 -
it => it.SelectedMemberInfo != null && it.SelectedMemberInfo.Name == PropertyNameHere)
如果您有可能在父集合中有 null 项,您还需要对其进行 null 检查 -
it => it?.SelectedMemberInfo?.Name == PropertyNameHere
【讨论】:
更新了问题并尝试了您的建议,但仍然为空参考以上是关于如何在 FluentAssertions 中使用方法的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 FluentAssertions 在 XUnit 中测试 MediatR 处理程序
如何在 FluentAssertions 中为集合中的属性使用排除?
如何在 FluentAssertions 中使用 Excluding 来排除 Dictionary 中的特定 KeyValue 对
如何使用 FluentAssertions 4.x 版断言异常?