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