如何在 FluentAssertions 中为集合中的属性使用排除?

Posted

技术标签:

【中文标题】如何在 FluentAssertions 中为集合中的属性使用排除?【英文标题】:How to use Exclude in FluentAssertions for property in collection? 【发布时间】:2014-04-04 06:05:45 【问题描述】:

我有两个班级:

public class ClassA

  public int? ID get; set;
  public IEnumerable<ClassB> Children get; set;


public class ClassB

  public int? ID get; set;
  public string Name get; set;

我想使用流利的断言来与 ClassA 实例进行比较。但是我想忽略 ID(因为 ID 将在保存后分配)。

我知道我能做到:

expectedA.ShouldBeEquivalentTo(actualA, options => options.Excluding(x => x.PropertyPath == "Children[0].ID"));

我显然可以为集合中的每个 ClassB 重复。但是,我正在寻找一种排除所有 ID 的方法(而不是对每个元素进行排除)。

我已阅读 this question,但是如果我删除 [0] 索引器,断言将失败。

这可能吗?

【问题讨论】:

【参考方案1】:

怎么样?

expected.ShouldBeEquivalentTo(actualA, options => options.Excluding(su => 
   (su.RuntimeType == typeof(ClassB)) && (su.PropertyPath.EndsWith("Id")));`

或者您可以在属性路径上进行正则表达式匹配,例如

expected.ShouldBeEquivalentTo(actualA, options => options.Excluding(su => (Regex.IsMatch
   ("Children\[.+\]\.ID"));

我其实很喜欢最后一个,但是正则表达式的东西使它有点难以阅读。也许我应该扩展ISubjectInfo 使用一种方法来匹配通配符模式的路径,以便您可以这样做:

expected.ShouldBeEquivalentTo(actualA, options => options
  .Excluding(su => su.PathMatches("Children[*].ID")));

【讨论】:

我将把这个标记为答案,因为扩展方法中的正则表达式是我最终采用的方法 在最新版本的 FluentAssertions 中这有什么变化?我不确定PropertyPath 是否还在 我尝试了这两个选项都没有成功,但能够修复 RegEx 选项以使用当前版本 - 请参阅 ***.com/questions/22142576/… 。顺便说一下,PropertyPath 的新名称是 SelectedMemberPath Regex.IsMatch(x.SelectedMemberPath, @"Children\[\d+\]\.ID") FluentAssertions v6 删除了 SelectedMemberPath,这里的解决方案是: options => options.Excluding((IMemberInfo x) => x.DeclaringType == typeof(ClassB) && x.Path.EndsWith("Id") )【参考方案2】:

我刚刚遇到了一个类似的问题,最新版本的 FluentAssertions 改变了一些事情。

我的对象包含其他对象的字典。字典中的对象包含我要排除的其他对象。我的场景是围绕测试 Json 序列化而忽略某些属性。

这对我有用:

gotA.ShouldBeEquivalentTo(expectedB , config => 
  config
    .Excluding(ctx => ctx.SelectedMemberInfo.MemberType == typeof(Venue))
    .Excluding(ctx => ctx.SelectedMemberInfo.MemberType == typeof(Exhibit))
    .Excluding(ctx => ctx.SelectedMemberInfo.MemberType == typeof(Content))
    .Excluding(ctx => ctx.SelectedMemberInfo.MemberType == typeof(Survey))
    .Excluding(ctx => ctx.SelectedMemberInfo.MemberType == typeof(Media))
  );

花了一些时间弄清楚如何做,但它真的很有用!

【讨论】:

对于它的价值,你也可以传入一个匿名对象作为自 FA 5 以来的期望,并且只包含你关心的属性。【参考方案3】:

简单的方法是直接在集合上设置断言,并结合ClassA等价断言的排除:

expectedA.ShouldBeEquivalentTo(expectedB,
   o => o.Excluding(s => s.PropertyInfo.Name == "Children"));
expectedA.Children.ShouldBeEquivalentTo(expectedB.Children,
   o => o.Excluding(s => s.PropertyInfo.Name = "Id"));

【讨论】:

我认为 Propertyinfo 已经不存在了。 SelectedMemberInfo.Name 应该这样做。【参考方案4】:

基于Dennis Doomen‘s answer 的正则表达式匹配想法,我能够使其工作

expected.ShouldBeEquivalentTo(actualA, options =>
  options.Excluding(su => 
     (Regex.IsMatch(su.SelectedMemberPath, "Children\\[.+\\].ID"));

与丹尼斯答案的不同之处:传递 su.SelectedMemberPath,双反斜杠以转义方括号。

【讨论】:

【参考方案5】:

ShouldBeEquivalentTo 方法现在似乎已过时,为了获得accepted answer 的路径,您可以使用Excluding 重载和IMemberInfo.SelectedMemberPath

expected.Should().BeEquivalentTo(actualA, options => 
    options.Excluding((IMemberInfo mi) => mi.SelectedMemberPath.EndsWith("ID")));

【讨论】:

【参考方案6】:

这里有一些有效的答案,但我要添加另一个不涉及字符串类型表达式的答案。

expectedA.ShouldBeEquivalentTo(expectedB, o => o.Excluding(s => s.Children));
expectedA.Children.ShouldBeEquivalentTo(expectedB.Children, o => o.Excluding(s => s.Id));

【讨论】:

【参考方案7】:

最简单的方法是:

expected.ShouldBeEquivalentTo(actual, config => config.ExcludingMissingMembers());

【讨论】:

OP 要求排除一些现有(非缺失)成员。【参考方案8】:

一个可以传递表达式列表的扩展类

public static class FluentAssertionsExtensions 
    public static EquivalencyAssertionOptions<T> ExcludingNextProperties<T>(
        this EquivalencyAssertionOptions<T> options,
        params Expression<Func<T, object>>[] expressions) 
        foreach (var expression in expressions) 
            options.Excluding(expression);
        

        return options;
    

用法

actual.Should().BeEquivalentTo(expected, 
            config => config.ExcludingNextProperties(
                o => o.Id, 
                o => o.CreateDateUtc))

【讨论】:

【参考方案9】:

我认为语法类似于

       actual.Should().BeEquivalentTo(
        expected, 
        config => config.Excluding(o => o.Id).Excluding(o => o.CreateDateUtc) );

【讨论】:

以上是关于如何在 FluentAssertions 中为集合中的属性使用排除?的主要内容,如果未能解决你的问题,请参考以下文章

FluentAssertions:如何在每对元素上使用自定义比较来比较两个集合?

如何使用 FluentAssertions 测试嵌套集合

FluentAssertions:如何指定该集合应包含一定数量的匹配谓词的元素?

FluentAssertions:如何指定该集合应包含一定数量的匹配谓词的元素?

如何将子集集合按值(结构平等)与 FluentAssertions 进行比较?

FluentAssertions Should.Equal 在集合上,包含空值