如何使用流畅断言(fluent-assertions)断言集合中的所有项?

34

假设我想测试一个返回以下类型一堆项目的方法,使用fluent-assertions来确保所有项目都将其IsActive标志设置为true

public class Item
{
    public bool IsActive { get; set; }
}
为了实现这一点,我可以简单地遍历整个集合并在foreach循环中逐个断言每个项:
var items = CreateABunchOfActiveItems();
foreach (var item in items)
{
    item.IsActive.Should().BeTrue("because I said so!");
}

但是有没有一种更流畅的方法可以同时断言整个集合中的每个项目?

3个回答

64

推荐的方法是使用OnlyContain

items.Should().OnlyContain(x => x.IsActive, "because I said so!");

这些也可以使用:

items.All(x => x.IsActive).Should().BeTrue("because I said so!");

items.Select(x => x.IsActive.Should().BeTrue("because I said so!"))
     .All(x => true); 

注意,最后一行 (.All(x => true)) 强制前面的 Select 对每个项目执行。


7
值得一提的是,这两个选项并不等价:.OnlyContain 要求集合不能为空,而 .All().Should().BeTrue() 则不要求。 - Aleksei

6

将 foreach 循环替换为 foreach 方法可能会有所帮助(至少会有点作用)。

var items = CreateABunchOfActiveItems();
items.ForEach(item => item.IsActive.Should().BeTrue("because I said so, too!"));

我认为这种语法比传统的foreach循环更加流畅 :)

如果你的方法CreateABunchOfActiveItems返回一个IEnumerable,那么它就没有定义ForEach方法。但是它可以很容易地作为扩展方法实现:

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumeration, 
    Action<T> action)
{
    // I use ToList() to force a copy, otherwise your action 
    // coud affect your original collection of items!. If you are confortable 
    // with that, you can ommit it
    foreach (T item in enumeration.ToList())
    {
        action(item);
        yield return item;
    }
}

这也是一种有效的方法 - 并且有提供ForEach扩展的库。但我主要是在寻找是否有一种方法可以使用流畅断言库本地实现这种方式。 - Spontifixus
2
还要注意,ToList() 已经枚举了原始集合,然后 foreach 循环再次枚举它... - Spontifixus
是的,我知道在处理大量操作(许多项目、数据库连接、文件读取等)时可能不是最佳方法,但对于我的日常测试来说很适合。 - Joel

2
使用AllSatisfy(),该方法在版本6.5.0中添加,具体请参考https://fluentassertions.com/collections/
在你的情况下,应该是这样的:
var items = CreateABunchOfActiveItems();
items.Should().AllSatisfy(
    i => i.IsActive.Should().BeTrue("because I said so!")
);

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