如何在 FluentAssertions 中使用 Excluding 来排除 Dictionary 中的特定 KeyValue 对
Posted
技术标签:
【中文标题】如何在 FluentAssertions 中使用 Excluding 来排除 Dictionary 中的特定 KeyValue 对【英文标题】:How to use Excluding in FluentAssertions to exclude specific KeyValue pair in Dictionary 【发布时间】:2018-04-29 05:10:04 【问题描述】:我正在使用 FluentAssertions 和 ShouldBeEquivalentTo
来比较两个 Dictionary<string, string>
类型的字典,但想排除一个或多个特定的 KeyValue 对(因为在这种情况下它们包含时间戳)。如何做到这一点?
我尝试过类似:opt => opt.Excluding(x => x.Single(kv => kv.Key == "MySearchKey"))
但这会导致错误,例如:Message: System.ArgumentException : Expression <Convert(x.Single(kv => (kv.Key == "MySearchKey")))> cannot be used to select a member.
我想要的可能吗?或者我应该只排除值而不是对(这可能更好,因为那时将检查密钥的存在)?谢谢!
【问题讨论】:
为什么不用linq排除键值对并比较结果 @Nkosi,感谢您的建议,我现在正在使用类似的过滤方法(如下 Jonas 所建议的)。 【参考方案1】:Excluding()
旨在排除 type 的成员,而不是排除 collection 的成员,有关详细信息,请参阅 documentation。
注意:以下代码适用于 Fluent Assertions 的当前稳定版本 4.19.4。
示例:
您想要比较 Person
和 PersonDTO
的实例,但 Person
包含要从对象比较中排除的 AnotherProperty
。
var person = new Person
FirstName = "John",
LastName = "McClane",
AnotherProperty = 42
;
var personDTO = new PersonDTO
FirstName = "John",
LastName = "McClane"
;
您可以在此处使用Exclude
排除某个类型的成员。
person.ShouldBeEquivalentTo(personDTO, options => options.Excluding(e => e.AnotherProperty));
在您的具体情况下,我不会使用ShouldBeEquivalentTo
。
考虑这两个字典实例,您想省略 collection 的成员,这里是 Key == "unknown"
的成员。
var actual = new Dictionary<string, int>
["one"] = 1,
["two"] = 2,
["three"] = 3,
["unknown"] = -1,
["fail"] = -2
;
var expected = new Dictionary<string, int>
["one"] = 1,
["two"] = 2,
["three"] = 3
;
您可以过滤掉不需要的键值对:
IEnumerable<KeyValuePair<string, int>> filtered = actual.Where(e => e.Key != "unknown");
现在断言将在两个IEnumerable<KeyValuePair<string, int>>
s之间
filtered.Should().Equal(expected);
这将给出以下断言失败消息:
FluentAssertions.Execution.AssertionFailedException: 'Expected collection to be equal to [one, 1], [two, 2], [three, 3], but [one, 1], [two, 2], [three, 3], [fail, -2] contains 1 item(s) too many.'
否则将过滤后的枚举转回字典:
Dictionary<string, int> filteredDict = actual.Where(e => e.Key != "unknown")
.ToDictionary(e => e.Key, e => e.Value);
您现在将再次比较Dictionary<string, int>
s:
filteredDict.Should().Equal(expected);
这将给出以下断言失败消息:
FluentAssertions.Execution.AssertionFailedException: 'Expected dictionary to be equal to [one, 1], [two, 2], [three, 3], but found additional keys "fail".'
如果想使用第二种方法并且您经常这样做,您可以创建扩展方法来提取从测试方法中删除成员的逻辑。
public static class DictionaryExtensions
public static IDictionary<TKey, TValue> ExceptKeys<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TKey[] keys)
if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
if (keys == null) throw new ArgumentNullException(nameof(keys));
return dictionary.Where(e => !keys.Contains(e.Key)).ToDictionary(e => e.Key, e => e.Value);
public static IDictionary<TKey, TValue> ExceptValues<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TValue[] values)
if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
if (values == null) throw new ArgumentNullException(nameof(values));
return dictionary.Where(e => !values.Contains(e.Value)).ToDictionary(e => e.Key, e => e.Value);
你现在可以写一个我认为更清晰简洁的测试:
actual.ExceptKeys("unknown").Should().Equal(expected);
【讨论】:
乔纳斯,感谢您非常详尽的解释!我习惯了 ShouldBeEquivalentTo,因为我大部分时间都将对象与对象进行比较。比较字典时,应该().Equal() 确实要好得多。我也切换到你的过滤解决方案。不错的方法,它完全适合我的需求。再次感谢! 请注意,ExceptKeys 和 exceptValues 应谨慎使用,因为它们不会保留原始字典的字典键的相等比较器。以上是关于如何在 FluentAssertions 中使用 Excluding 来排除 Dictionary 中的特定 KeyValue 对的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 FluentAssertions 在 XUnit 中测试 MediatR 处理程序
如何在 FluentAssertions 中为集合中的属性使用排除?
如何在 FluentAssertions 中使用 Excluding 来排除 Dictionary 中的特定 KeyValue 对
如何使用 FluentAssertions 4.x 版断言异常?