如何使用 Fluent Assertion 比较两个因属性而异的集合?

Posted

技术标签:

【中文标题】如何使用 Fluent Assertion 比较两个因属性而异的集合?【英文标题】:How to compare two collections that vary by properties using Fluent Assertion? 【发布时间】:2018-06-05 09:37:00 【问题描述】:

我有公共类 RuleInfo,它是从内部类 Rule 创建的。

private static RuleInfo CreateRuleInfo(Rule r)

    return new RuleInfo
    
        RuleCode = r.RuleId,
        DisplayName = r.RuleCode,
        Description = r.Description,
        LegacyRuleCode = null
    ;

它们的属性名称各不相同,因此 ShouldBeEquivalentTo()ShouldAllBeEquivalentTo() 不起作用。

现在我正在手动/明确地比较它们:

foreach (var x in Enumerable.Zip(infs, rules, (i, r) => new  Info = i, Rule = r ))

    x.Info.ShouldBeEquivalentTo(
        new
        
            RuleCode = x.Rule.RuleId,
            DisplayName = x.Rule.RuleCode,
            Description = x.Rule.Description,
            LegacyRuleCode = (string)null
        );

有没有更好、更紧凑、更简洁、更易读的方式?

【问题讨论】:

github.com/fluentassertions/fluentassertions/issues/535 【参考方案1】:

一个选项是在全局选项配置中添加自定义等效步骤:

class DifferentObjectsEquivalencyStep<T1, T2> : IEquivalencyStep 
    private readonly Func<T1, T2> _converter;

    public DifferentObjectsEquivalencyStep(Func<T1, T2> converter) 
        _converter = converter;
    

    public bool CanHandle(IEquivalencyValidationContext context, IEquivalencyAssertionOptions config) 
        return context.Subject is T1 && context.Expectation is T2 || context.Subject is T2 && context.Expectation is T1;
    

    public bool Handle(IEquivalencyValidationContext context, IEquivalencyValidator parent, IEquivalencyAssertionOptions config)             
        var first = context.Subject is T1 ? (T1) context.Subject : (T1) context.Expectation;
        var second = context.Subject is T2 ? (T2) context.Subject : (T2) context.Expectation;
        second.ShouldBeEquivalentTo(_converter(first));
        return true;
    

然后在进行所有比较之前的某个地方:

AssertionOptions.AssertEquivalencyUsing(c => c.Using(
            new DifferentObjectsEquivalencyStep<Rule, RuleInfo>(CreateRuleInfo)));

之后,常规的ShouldBeEquivalentTo(和ShouldAllBeEquivalentTo)将起作用:

rule.ShouldBeEquivalentTo(info);

【讨论】:

感谢您的回答!我从中了解了更多关于 FA API 的信息。刚刚发现乔纳斯的答案很短:)【参考方案2】:

不幸的是,目前没有办法在比较不同类型时指定属性之间的映射。有一个关于它的公开issue。

这是比较两个集合的另一种方法的示例。 请注意,我假设 == 执行值相等。 因此,如果您的所有属性都是 intstring,那么您就安全了。

ruleInfos.Should().Equal(rules, (ruleInfo, rule) =>
    ruleInfo.RuleCode == rule.RuleId
     && ruleInfo.DisplayName == rule.RuleCode
    && ruleInfo.Description == rule.Description
);

例如没有== 重载的引用类型,您需要优雅地处理空值,例如

(PropertyA == PropertyB) || (PropertyA?.Equals(PropertyB) == true

【讨论】:

以上是关于如何使用 Fluent Assertion 比较两个因属性而异的集合?的主要内容,如果未能解决你的问题,请参考以下文章

Fluent Assertion - 比较忽略空值的模型属性

如何检查是不是可以在 Fluent Assertion 中使用 ContainValue 验证类型类的字典

fluent中,怎样对颗粒的轨迹进行数值模拟?

fluent 风速 怎么算区域平均值

fluent中VOF法如何模拟正确的水深

Fluent Assertions 能否对 IEnumerable<string> 使用不区分字符串的比较?