如何使用Fluent Assertion比较具有不同属性的两个集合?

4

我有一个公共类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
        });
}

有没有更好的、更紧凑的、不那么明确的、更易读的方法?

https://github.com/fluentassertions/fluentassertions/issues/535 - desmondgc
2个回答

7

一种方法是将自定义等效步骤添加到全局选项配置中:

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的知识。只是发现Jonas的回答比较简短 :) - abatishchev

3
很遗憾,目前还没有一种方法可以在比较不同类型时指定属性之间的映射关系。关于这个问题有一个未解决的问题
以下是另一种比较两个集合的示例。 请注意,我假设 == 执行值相等性。 因此,如果您的所有属性都是 int 和 string ,则安全无忧。
ruleInfos.Should().Equal(rules, (ruleInfo, rule) =>
    ruleInfo.RuleCode == rule.RuleId
     && ruleInfo.DisplayName == rule.RuleCode
    && ruleInfo.Description == rule.Description
);

例如,对于没有重载==的引用类型,您需要使用如下方式优雅地处理null值。
(PropertyA == PropertyB) || (PropertyA?.Equals(PropertyB) == true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接