Collections

Edit this page

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.

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.

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.

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.
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:

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.

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.

collection.Select(x => x.SomeProperty).Should().OnlyHaveUniqueItems();

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

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:

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:

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:

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:

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:

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:

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