33

Say I want to test a method returning a bunch of items of the following type using fluent-assertions to ensure that all items have their IsActive-flag set to true:

public class Item
{
    public bool IsActive { get; set; }
}

To achieve that I could simply iterate over the collection and assert every item separately in a foreach-loop:

var items = CreateABunchOfActiveItems();
foreach (var item in items)
{
    item.IsActive.Should().BeTrue("because I said so!");
}

But is there a more fluent way to assert every item in the whole collection at once?

Spontifixus
  • 6,570
  • 9
  • 45
  • 63

3 Answers3

62

The recommended way is to use OnlyContain:

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

These will also work:

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); 

Note that the last line (.All(x => true)) forces the previous Select to execute for each item.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • 5
    It worths mentioning that these two options are not equivalent: ```.OnlyContain``` requires collection to be not empty, while ```.All().Should().BeTrue()``` - does not. – Aleksei Jul 27 '20 at 13:15
6

Something like replacing your foreach loop with a foreach method should do the trick (at least a little bit).

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

I find this syntax a little bit more fluent than traditional foreach loop :)

ForEach method is not defined if your method CreateABunchOfActiveItems returns an IEnumerable. But it can be easily implemented as an extension method:

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;
    }
}
Joel
  • 7,401
  • 4
  • 52
  • 58
  • This is also a valid approach - And there are libraries providing the `ForEach`-extension. But I was mainly looking if there is a way to do this kind of natively with the fluent-assertion library. – Spontifixus Sep 19 '13 at 16:44
  • 2
    And also note, that `ToList()` already enumerates the original collection, which then gets enumerated once again by the `foreach`-loop... – Spontifixus Sep 19 '13 at 16:46
  • Yes, I'm aware that it may not be the best approach when dealing with heavy operations (many items, db connections, filereading, etc.) but it suits me for my daily testing. – Joel Sep 19 '13 at 17:13
1

Use AllSatisfy(), which was added in v. 6.5.0 as per https://fluentassertions.com/collections/.

In your case, it would be:

var items = CreateABunchOfActiveItems();
items.Should().AllSatisfy(
    i => i.IsActive.Should().BeTrue("because I said so!")
);
Grzegorz Smulko
  • 2,525
  • 1
  • 29
  • 42