Fluent Assertions Documentation
In This Topic
    Collections
    In This Topic

    A collection object in .NET is so versatile that the number of assertions on them require the same level of versatility. Most, if not all, are so self-explanatory that we'll just list them here.

    C#
    Copy Code
    IEnumerable<int> collection = new[] { 1, 2, 5, 8 };
    
    collection.Should().NotBeEmpty()
        .And.HaveCount(4)
        .And.ContainInOrder(new[] { 2, 5 })
        .And.ContainItemsAssignableTo<int>();
    
    collection.Should().Equal(new List<int> { 1, 2, 5, 8 });
    collection.Should().Equal(1, 2, 5, 8);
    collection.Should().NotEqual(8, 2, 3, 5);
    collection.Should().BeEquivalentTo(new[] {8, 2, 1, 5});
    collection.Should().NotBeEquivalentTo(new[] {8, 2, 3, 5});
    
    collection.Should().HaveCount(c => c > 3)
      .And.OnlyHaveUniqueItems();
    
    collection.Should().HaveCountGreaterThan(3);
    collection.Should().HaveCountGreaterThanOrEqualTo(4);
    collection.Should().HaveCountLessThanOrEqualTo(4);
    collection.Should().HaveCountLessThan(5);
    collection.Should().NotHaveCount(3);
    collection.Should().HaveSameCount(new[] { 6, 2, 0, 5 });
    collection.Should().NotHaveSameCount(new[] { 6, 2, 0 });
    
    collection.Should().StartWith(1);
    collection.Should().StartWith(new[] { 1, 2 });
    collection.Should().EndWith(8);
    collection.Should().EndWith(new[] { 5, 8 });
    
    collection.Should().BeSubsetOf(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, });
    
    collection.Should().ContainSingle();
    collection.Should().ContainSingle(x => x > 3);
    collection.Should().Contain(8)
      .And.HaveElementAt(2, 5)
      .And.NotBeSubsetOf(new[] {11, 56});
    
    collection.Should().Contain(x => x > 3);
    collection.Should().Contain(collection, "", 5, 6); // It should contain the original items, plus 5 and 6.
    
    collection.Should().OnlyContain(x => x < 10);
    collection.Should().ContainItemsAssignableTo<int>();
    collection.Should().NotContainItemsAssignableTo<string>();
    
    collection.Should().ContainInOrder(new[] { 1, 5, 8 });
    collection.Should().NotContainInOrder(new[] { 5, 1, 2 });
    
    collection.Should().ContainInConsecutiveOrder(new[] { 2, 5, 8 });
    collection.Should().NotContainInConsecutiveOrder(new[] { 1, 5, 8});
    
    collection.Should().NotContain(82);
    collection.Should().NotContain(new[] { 82, 83 });
    collection.Should().NotContainNulls();
    collection.Should().NotContain(x => x > 10);
    
    object boxedValue = 2;
    collection.Should().ContainEquivalentOf(boxedValue); // Compared by object equivalence
    object unexpectedBoxedValue = 82;
    collection.Should().NotContainEquivalentOf(unexpectedBoxedValue); // Compared by object equivalence
    
    const int successor = 5;
    const int predecessor = 5;
    collection.Should().HaveElementPreceding(successor, element);
    collection.Should().HaveElementSucceeding(predecessor, element);
    
    collection.Should().BeEmpty();
    collection.Should().BeNullOrEmpty();
    collection.Should().NotBeNullOrEmpty();
    
    IEnumerable<int> otherCollection = new[] { 1, 2, 5, 8, 1 };
    IEnumerable<int> anotherCollection = new[] { 10, 20, 50, 80, 10 };
    collection.Should().IntersectWith(otherCollection);
    collection.Should().NotIntersectWith(anotherCollection);
    
    var singleEquivalent = new[] { new { Size = 42 } };
    singleEquivalent.Should().ContainSingle()
        .Which.Should().BeEquivalentTo(new { Size = 42 });

    Asserting that a collection contains items in a certain order is as easy as using one of the several overloads of BeInAscendingOrder or BeInDescendingOrder. The default overload will use the default Comparer for the specified type, but overloads also exist that take an IComparer<T>, a property expression to sort by an object's property, or a lambda expression to avoid the need for IComparer<T> implementations.

    C#
    Copy Code
    collection.Should().BeInAscendingOrder();
    collection.Should().BeInDescendingOrder();
    collection.Should().NotBeInAscendingOrder();
    collection.Should().NotBeInDescendingOrder();

    Since 6.9.0 there is a slight change in how culture is taken into comparison. Now by default StringComparer.Ordinal is used to compare strings. If you want to overrule this behavior use the IComparer<T> overload. The use case is e.g. if you get data from a database ordered by culture aware sort order.

    C#
    Copy Code
    collection.Should().BeInAscendingOrder(item => item.SomeProp, StringComparer.CurrentCulture);
    collection.Should().BeInDescendingOrder(item => item.SomeProp, StringComparer.CurrentCulture);
    collection.Should().NotBeInAscendingOrder(item => item.SomeProp, StringComparer.CurrentCulture);
    collection.Should().NotBeInDescendingOrder(item => item.SomeProp, StringComparer.CurrentCulture);

    For String collections there are specific methods to assert the items. For the ContainMatch and NotContainMatch methods we support wildcards.

    The pattern can be a combination of literal and wildcard characters, but it doesn't support regular expressions.

    The following wildcard specifiers are permitted in the pattern:

    Wildcard specifier Matches
    * (asterisk) Zero or more characters in that position.
    ? (question mark) Exactly one character in that position.
    C#
    Copy Code
    IEnumerable<string> stringCollection = new[] { "build succeeded", "test failed" };
    stringCollection.Should().AllBe("build succeeded");
    stringCollection.Should().ContainMatch("* failed");

    In order to assert presence of an equivalent item in a collection applying Object graph comparison rules, use this:

    C#
    Copy Code
    collection.Should().ContainEquivalentOf(boxedValue);
    collection.Should().NotContainEquivalentOf(unexpectedBoxedValue)

    Those last two methods can be used to assert a collection contains items in ascending or descending order. For simple types that might be fine, but for more complex types, it requires you to implement IComparable, something that doesn't make a whole lot of sense in all cases. That's why we offer overloads that take an expression.

    C#
    Copy Code
    collection.Should().BeInAscendingOrder(x => x.SomeProperty);
    collection.Should().BeInDescendingOrder(x => x.SomeProperty);
    collection.Should().NotBeInAscendingOrder(x => x.SomeProperty);
    collection.Should().NotBeInDescendingOrder(x => x.SomeProperty);

    When asserting on a projection of a collection the failure message will be less descriptive as it only knows about the projected value and not object containing that property.

    C#
    Copy Code
    collection.Select(x => x.SomeProperty).Should().OnlyHaveUniqueItems();

    Therefore we offer two overloads that takes an expression to select the property.

    C#
    Copy Code
    collection.Should().OnlyHaveUniqueItems(x => x.SomeProperty);
    collection.Should().NotContainNulls(x => x.SomeProperty);

    Special overloads of Equal(), StartWith and EndWith take a lambda that is used for checking the two collections without relying on the type’s Equals() method. Consider for instance two collections that contain some kind of domain entity persisted to a database and then reloaded. Since the actual object instance is different, if you want to make sure a particular property was properly persisted, you usually do something like this:

    C#
    Copy Code
    persistedCustomers.Select(c => c.Name).Should().Equal(customers.Select(c => c.Name));
    persistedCustomers.Select(c => c.Name).Should().StartWith(customers.Select(c => c.Name));
    persistedCustomers.Select(c => c.Name).Should().EndWith(customers.Select(c => c.Name));

    With these new overloads, you can rewrite them into:

    C#
    Copy Code
    persistedCustomers.Should().Equal(customers, (c1, c2) => c1.Name == c2.Name);
    persistedCustomers.Should().StartWith(customers, (c1, c2) => c1.Name == c2.Name);
    persistedCustomers.Should().EndWith(customers, (c1, c2) => c1.Name == c2.Name);

    You can also perform assertions on all elements of a collection:

    C#
    Copy Code
    IEnumerable<BaseType> collection = new BaseType[] { new DerivedType() };
    
    collection.Should().AllBeAssignableTo<DerivedType>();
    collection.Should().AllBeOfType<DerivedType>();
    collection.Should().AllBeEquivalentTo(referenceObject);

    In case if you need to perform individual assertions on all elements of a collection, you can assert each element separately in the following manner:

    C#
    Copy Code
    var collection = new []
    {
        new { Id = 1, Name = "John", Attributes = new string[] { } },
        new { Id = 2, Name = "Jane", Attributes = new string[] { "attr" } }
    };
    collection.Should().SatisfyRespectively(
        first =>
        {
            first.Id.Should().Be(1);
            first.Name.Should().StartWith("J");
            first.Attributes.Should().NotBeNull();
        },
        second =>
        {
            second.Id.Should().Be(2);
            second.Name.Should().EndWith("e");
            second.Attributes.Should().NotBeEmpty();
        });

    If you need to perform the same assertion on all elements of a collection:

    C#
    Copy Code
    var collection = new []
    {
        new { Id = 1, Name = "John", Attributes = new string[] { } },
        new { Id = 2, Name = "Jane", Attributes = new string[] { "attr" } }
    };
    collection.Should().AllSatisfy(x =>
    {
        x.Id.Should().BePositive();
        x.Name.Should().StartWith("J");
        x.Attributes.Should().NotBeNull();
    });

    If you need to perform individual assertions on all elements of a collection without setting expectation about the order of elements:

    C#
    Copy Code
    var collection = new []
    {
        new { Id = 1, Name = "John", Attributes = new string[] { } },
        new { Id = 2, Name = "Jane", Attributes = new string[] { "attr" } }
    };
    
    collection.Should().Satisfy(
        e => e.Id == 2 && e.Name == "Jane" && e.Attributes == null,
        e => e.Id == 1 && e.Name == "John" && e.Attributes != null && e.Attributes.Length > 0);