如何使用 Fluent Assertion 比较因属性而异的两个集合?
How to compare two collections that vary by properties using Fluent Assertion?
我有 public class RuleInfo
是从内部创建的 class Rule
.
private static RuleInfo CreateRuleInfo(Rule r)
{
return new RuleInfo
{
RuleCode = r.RuleId,
DisplayName = r.RuleCode,
Description = r.Description,
LegacyRuleCode = null
};
}
它们的属性名称各不相同,因此 ShouldBeEquivalentTo()
或 ShouldAllBeEquivalentTo()
不起作用。
现在我正在比较它们manually/explicitly:
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
});
}
是否有更好、更紧凑、更简洁、更易读的方式?
遗憾的是,当前无法在比较不同类型时指定属性之间的映射。关于它有一个开放的issue。
下面是比较两个集合的另一种方法的示例。
请注意,我假设 ==
执行值相等。
因此,如果您所有的财产都是 int
和 string
,那么您就安全到家了。
ruleInfos.Should().Equal(rules, (ruleInfo, rule) =>
ruleInfo.RuleCode == rule.RuleId
&& ruleInfo.DisplayName == rule.RuleCode
&& ruleInfo.Description == rule.Description
);
例如没有重载 ==
的引用类型,您需要优雅地处理空值,例如
(PropertyA == PropertyB) || (PropertyA?.Equals(PropertyB) == true
一个选项是向全局选项配置添加自定义等效步骤:
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);
我有 public class RuleInfo
是从内部创建的 class Rule
.
private static RuleInfo CreateRuleInfo(Rule r)
{
return new RuleInfo
{
RuleCode = r.RuleId,
DisplayName = r.RuleCode,
Description = r.Description,
LegacyRuleCode = null
};
}
它们的属性名称各不相同,因此 ShouldBeEquivalentTo()
或 ShouldAllBeEquivalentTo()
不起作用。
现在我正在比较它们manually/explicitly:
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
});
}
是否有更好、更紧凑、更简洁、更易读的方式?
遗憾的是,当前无法在比较不同类型时指定属性之间的映射。关于它有一个开放的issue。
下面是比较两个集合的另一种方法的示例。
请注意,我假设 ==
执行值相等。
因此,如果您所有的财产都是 int
和 string
,那么您就安全到家了。
ruleInfos.Should().Equal(rules, (ruleInfo, rule) =>
ruleInfo.RuleCode == rule.RuleId
&& ruleInfo.DisplayName == rule.RuleCode
&& ruleInfo.Description == rule.Description
);
例如没有重载 ==
的引用类型,您需要优雅地处理空值,例如
(PropertyA == PropertyB) || (PropertyA?.Equals(PropertyB) == true
一个选项是向全局选项配置添加自定义等效步骤:
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);