Skip to main content

Items

Describes how to verify the number of items, how many items meet an expectation, a single item or the item at an index.

ExpectationNegatedSummary
HasCountnegated comparisonhas the expected number of items
IsEmptyIsNotEmptyhas no items
All(), Any(), …None()the selected number of items meet an expectation
HasSinglehas exactly one (matching) item
HasItemDoesNotHaveItemhas the expected item at an index or at any index
HasItemThatDoesNotHaveItemThathas an item that meets an expectation at an index or at any index

Count​

You can verify the number of items in a collection:

IEnumerable<string> songs = ["Come Together", "Something", "Let It Be"];

await Expect.That(songs).HasCount(3);
await Expect.That(songs).HasCount().GreaterThan(2);
await Expect.That(songs).HasCount().NotBetween(5).And(10);

The Has… expectations for a number or a TimeSpan, e.g. HasLength(), HasCount(), HasYear() or HasMajor(), continue with one of the following comparisons, each with a negated counterpart:

ComparisonNegatedSucceeds when the value is
EqualTo(x)NotEqualTo(x)equal to x
GreaterThan(x)NotGreaterThan(x)greater than x
GreaterThanOrEqualTo(x)NotGreaterThanOrEqualTo(x)greater than or equal to x
LessThan(x)NotLessThan(x)less than x
LessThanOrEqualTo(x)NotLessThanOrEqualTo(x)less than or equal to x
Between(min).And(max)NotBetween(min).And(max)between min and max, both bounds included

Passing the value directly, e.g. HasLength(10), is a shorthand for EqualTo.

The expected value is nullable, e.g. to pass a value mapped from a property. As the actual value is never null, EqualTo(null) fails and NotEqualTo(null) succeeds, while a comparison of order against null, such as GreaterThan(null) or Between(null).And(3), fails even when negated.

You can also verify that the collection is empty or not:

await Expect.That(Array.Empty<Track>()).IsEmpty();
await Expect.That(new[] { "Let It Be" }).IsNotEmpty();

Quantifiers​

You can add expectations that a certain number of items must meet. A quantifier selects how many:

QuantifierSucceeds when the expectation is met by
All()every item
Any()at least one item (a shorthand for AtLeast(1))
AtLeast(minimum)at least minimum items
AtMost(maximum)at most maximum items
Between(min).And(max)between min and max items, both bounds included
Exactly(expected)exactly expected items
LessThan(maximum)fewer than maximum items
MoreThan(minimum)more than minimum items
None()no item

and what the items must meet:

ExpectationSucceeds for an item that
ComplyWithmeets the nested expectation
Satisfysatisfies the predicate
AreEqualTois equal to the expected value
AreEquivalentTois equivalent to the expected value
Are<T>is of type T or a derived type
AreExactly<T>is exactly of type T
AreUniqueoccurs exactly once (AreNotUnique: more than once)

An empty collection satisfies All(), like it does Enumerable.All, so Expect.That(new int[0]).All().Satisfy(x => false) succeeds. In contrast, WithRecursiveInnerExceptions and HasRecursiveInnerExceptions fail for an exception without inner exceptions.

Nested expectation​

You can verify that items in a collection comply with an expectation on the individual items:

await Expect.That([1, 2, 3]).All().ComplyWith(item => item.IsLessThan(4));
await Expect.That([1, 2, 3]).Any().ComplyWith(item => item.IsEqualTo(2));
await Expect.That([1, 2, 3]).AtLeast(2).ComplyWith(item => item.IsGreaterThanOrEqualTo(2));
await Expect.That([1, 2, 3]).AtMost(1).ComplyWith(item => item.IsNegative());
await Expect.That([1, 2, 3]).Between(2).And(3).ComplyWith(item => item.IsPositive());
await Expect.That([1, 2, 3]).Exactly(1).ComplyWith(item => item.IsEqualTo(2));
await Expect.That([1, 2, 3]).None().ComplyWith(item => item.IsNegative());

Condition​

You can verify that items in a collection satisfy a condition:

Track[] tracks = [new() { Title = "Let It Be", PlayCount = 3 }, new() { Title = "Get Back", PlayCount = 0 }];

await Expect.That(tracks).Any().Satisfy(track => track.PlayCount > 0);
await Expect.That(tracks).None().Satisfy(track => track.Title == null);

Equality​

You can verify that the items in the collection are equal to the expected value:

await Expect.That([1, 1, 1]).All().AreEqualTo(1);

The items are compared by their default equality, unless you specify a custom comparer, equivalency, a tolerance or, for strings, one of the string options:

IEnumerable<Album> albums = //...
Album expected = //...

await Expect.That(albums).All().AreEqualTo(expected).Equivalent();
await Expect.That(albums).All().AreEqualTo(expected).Using(new AlbumComparer());
await Expect.That(albums).AtLeast(2).AreEquivalentTo(expected);
await Expect.That(["let it be", "LET IT BE"]).All().AreEqualTo("Let It Be").IgnoringCase();
await Expect.That([2.04, 2.02, 2.01]).All().AreEqualTo(2.0).Within(0.1);

Type​

You can verify that the items are of a given type, or exactly of that type:

IEnumerable<INotification> notifications = //...

await Expect.That(notifications).All().Are<INotification>();
await Expect.That(notifications).AtLeast(1).AreExactly<UserCreatedNotification>();
await Expect.That(notifications).None().Are(typeof(UserDeletedNotification));

Unique​

You can verify how many items in a collection occur exactly once:

await Expect.That([1, 2, 3]).All().AreUnique();
await Expect.That([1, 2, 3, 1]).AtLeast(1).AreNotUnique();
await Expect.That([1, 2, 1, 2]).None().AreUnique();
await Expect.That([1, 2, 3, 4, 5, 5]).AtLeast(4).AreUnique();

For objects, you can also verify the uniqueness of a member, and you can use a custom comparer or ignore the case of strings:

Album[] albums = //...

await Expect.That(albums).All().AreUnique(x => x.Title);
await Expect.That(albums).All().AreUnique().Using(new AlbumComparer());
await Expect.That(["Help!", "Revolver"]).All().AreUnique().IgnoringCase();

A set that was created with a custom comparer never holds two items that its comparer considers equal, so its items are unique, unless a custom comparer or a string option such as IgnoringCase() changes the comparison.

For dictionaries, verify the values instead, as the keys are unique by design.

Single item​

You can verify that the collection contains a single item, and continue with expectations on it with Which:

IEnumerable<int> values = [42];

await Expect.That(values).HasSingle();
await Expect.That(values).HasSingle().Which.IsGreaterThan(41);

You can also apply filters for the items:

IEnumerable<int> values = [1, 2, 3,];

await Expect.That(values).HasSingle().Matching(it => it > 2);

// Or with generic type:
IEnumerable<Person> persons = //...

await Expect.That(persons).HasSingle().Matching<Student>();
await Expect.That(persons).HasSingle().Matching<Student>(student => student.Courses.Count == 0);

// Similar to the expectations above, but verify the type exactly:
await Expect.That(persons).HasSingle().MatchingExactly<Student>();
await Expect.That(persons).HasSingle().MatchingExactly<Student>(student => student.Courses.Count == 0);

The awaited result is the single item:

IEnumerable<string> songs = ["Let It Be"];

string song = await Expect.That(songs).HasSingle();

Item at index​

You can verify that the collection contains an item that satisfies the expectation on a given index (or any index):

IEnumerable<string> songs = ["Two of Us", "Dig a Pony", "Across the Universe", "I Me Mine"];

await Expect.That(songs).HasItem("Dig a Pony").AtIndex(1); // at the zero-based index 1
await Expect.That(songs).HasItem("Across the Universe").AtIndex(1).FromEnd(); // at the zero-based index 1 from end
await Expect.That(songs).HasItem(it => it.StartsWith("I Me")); // at any index

You can also check that the item matches a specific type:

IEnumerable<INotification> values = //...

// Verify that the item at index 1 is of type `UserCreatedNotification`
await Expect.That(values).HasItem().Matching<UserCreatedNotification>().AtIndex(1);
// Verify that an item of type `UserDeletedNotification` for user with ID 3 exists
await Expect.That(values).HasItem().Matching<UserDeletedNotification>(x => x.UserId == 3);

// Similar to the expectations above, but verify the type exactly:
await Expect.That(values).HasItem().MatchingExactly<UserCreatedNotification>().AtIndex(1);
await Expect.That(values).HasItem().MatchingExactly<UserDeletedNotification>(x => x.UserId == 3);

You can also use expectations on the individual items:

IEnumerable<string> songs = ["Two of Us", "Dig a Pony", "Across the Universe", "I Me Mine"];

await Expect.That(songs).HasItemThat(it => it.IsEqualTo("Dig a Pony")).AtIndex(1);
await Expect.That(songs).HasItemThat(it => it.StartsWith("Across").And.EndsWith("Universe")); // at any index

Each of these expectations has a negated counterpart. It is satisfied when the index holds a different item, and also when the collection is too short to have an item at that index:

IEnumerable<string> songs = ["Two of Us", "Dig a Pony"];

await Expect.That(songs).DoesNotHaveItem("I Me Mine").AtIndex(1);
await Expect.That(songs).DoesNotHaveItem("Two of Us").AtIndex(4); // no item at index 4
await Expect.That(songs).DoesNotHaveItem().Matching(it => it.StartsWith("I Me")).AtIndex(1);
await Expect.That(songs).DoesNotHaveItemThat(it => it.StartsWith("I Me")).AtIndex(1);