Items
Describes how to verify the number of items, how many items meet an expectation, a single item or the item at an index.
| Expectation | Negated | Summary |
|---|---|---|
HasCount | negated comparison | has the expected number of items |
IsEmpty | IsNotEmpty | has no items |
All(), Any(), … | use None() | the selected number of items meet an expectation |
HasSingle | has exactly one (matching) item | |
HasItem | DoesNotHaveItem | has the expected item at an index or at any index |
HasItemThat | DoesNotHaveItemThat | has 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 That(songs).HasCount(3);
await That(songs).HasCount().GreaterThan(2);
await That(songs).HasCount().NotBetween(5).And(10);
The Has… expectations whose value is a number or a TimeSpan, e.g. HasLength(), HasCount(), HasYear() or
HasMajor(), continue with one of the following comparisons, each with a negated counterpart:
| Comparison | Negated | Succeeds 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. HasCount(3), is a shorthand for EqualTo.
Comparing with null
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 That(Array.Empty<Track>()).IsEmpty();
await That(new[] { "Let It Be" }).IsNotEmpty();
Quantifiers
You can verify that a certain number of items meet an expectation. A quantifier selects how many:
| Quantifier | Succeeds 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:
| Expectation | Succeeds for an item that |
|---|---|
ComplyWith | meets the nested expectation |
Satisfy | satisfies the predicate |
AreEqualTo | is equal to the expected value |
AreEquivalentTo | is equivalent to the expected value |
Are<T> | is of type T or a derived type |
AreExactly<T> | is exactly of type T |
AreUnique | occurs exactly once (AreNotUnique: more than once) |
An empty collection satisfies All(), like it does Enumerable.All, so
That(new int[0]).All().Satisfy(x => false) succeeds.
Nested expectation
You can verify that items in a collection comply with an expectation on the individual items:
IEnumerable<int> playCounts = [1, 2, 3];
await That(playCounts).All().ComplyWith(item => item.IsLessThan(4));
await That(playCounts).Any().ComplyWith(item => item.IsEqualTo(2));
await That(playCounts).AtLeast(2).ComplyWith(item => item.IsGreaterThanOrEqualTo(2));
await That(playCounts).AtMost(1).ComplyWith(item => item.IsNegative());
await That(playCounts).Between(2).And(3).ComplyWith(item => item.IsPositive());
await That(playCounts).Exactly(1).ComplyWith(item => item.IsEqualTo(2));
await That(playCounts).None().ComplyWith(item => item.IsNegative());
Items the nested expectation cannot answer
An item for which the nested expectation fails and its negation fails as well decides the result, because the
expectation could not answer it: the nested expectation threw (the exception becomes the InnerException), or the item
or an inspected member is null. So None().ComplyWith(item => item.StartsWith("Let")) fails for a null item, and so
does its negation. The same applies to HasItemThat and to collections compared with item
expectations or predicates, where in any order such an item only decides when it matches no other expected item.
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 That(tracks).Any().Satisfy(track => track.PlayCount > 0);
await That(tracks).None().Satisfy(track => track.Title == null);
Contains(predicate) verifies the same as Any().Satisfy(…), and
HasItem verifies the item at an index, see
choosing an expectation.
Equality
You can verify that the items in the collection are equal to the expected value:
IEnumerable<string> playlist = ["Let It Be", "Let It Be", "Let It Be"];
await That(playlist).All().AreEqualTo("Let It Be");
The items are compared like in the other collection expectations, so you can specify a custom comparer, equivalency, a tolerance or a string option:
IEnumerable<Album> albums = //...
Album expected = //...
await That(albums).All().AreEqualTo(expected).Equivalent();
await That(albums).All().AreEqualTo(expected).Using(new AlbumComparer());
await That(albums).AtLeast(2).AreEquivalentTo(expected);
await That(["let it be", "LET IT BE"]).All().AreEqualTo("Let It Be").IgnoringCase();
Type
You can verify that the items are of a given type, or exactly of that type:
IEnumerable<INotification> notifications = //...
await That(notifications).All().Are<INotification>();
await That(notifications).AtLeast(1).AreExactly<TrackAddedNotification>();
await That(notifications).None().Are(typeof(TrackRemovedNotification));
Unique
You can verify how many items in a collection occur exactly once:
await That(["Help!", "Yesterday", "Let It Be"]).All().AreUnique();
await That(["Help!", "Yesterday", "Let It Be", "Help!"]).AtLeast(1).AreNotUnique();
await That(["Help!", "Yesterday", "Help!", "Yesterday"]).None().AreUnique();
await That(["Help!", "Yesterday", "Let It Be", "Get Back", "Michelle", "Michelle"]).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 That(albums).All().AreUnique(x => x.Title);
await That(albums).All().AreUnique().Using(new AlbumComparer());
await That(["Help!", "Revolver"]).All().AreUnique().IgnoringCase();
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> playCounts = [42];
await That(playCounts).HasSingle();
await That(playCounts).HasSingle().Which.IsGreaterThan(41);
You can also apply filters for the items:
IEnumerable<int> playCounts = [1, 2, 3];
await That(playCounts).HasSingle().Matching(it => it > 2);
// Or with generic type:
IEnumerable<Artist> artists = //...
await That(artists).HasSingle().Matching<Band>();
await That(artists).HasSingle().Matching<Band>(band => band.Members.Count == 4);
// Similar to the expectations above, but verify the type exactly:
await That(artists).HasSingle().MatchingExactly<Band>();
await That(artists).HasSingle().MatchingExactly<Band>(band => band.Members.Count == 4);
The awaited result is the single item:
IEnumerable<string> songs = ["Let It Be"];
string song = await 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 That(songs).HasItem("Dig a Pony").AtIndex(1); // at the zero-based index 1
await That(songs).HasItem("Across the Universe").AtIndexFromEnd(1); // zero-based index 1 from the end
await 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 `TrackAddedNotification`
await That(values).HasItem().Matching<TrackAddedNotification>().AtIndex(1);
// Verify that an item of type `TrackRemovedNotification` for the track with ID 3 exists
await That(values).HasItem().Matching<TrackRemovedNotification>(x => x.TrackId == 3);
// Similar to the expectations above, but verify the type exactly:
await That(values).HasItem().MatchingExactly<TrackAddedNotification>().AtIndex(1);
await That(values).HasItem().MatchingExactly<TrackRemovedNotification>(x => x.TrackId == 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 That(songs).HasItemThat(it => it.IsEqualTo("Dig a Pony")).AtIndex(1);
await That(songs).HasItemThat(it => it.StartsWith("Across").And.EndsWith("Universe")); // at any index
At any index, HasItem(predicate) and HasItemThat verify the same as Any().Satisfy(…) and
Any().ComplyWith(…), see choosing an expectation.
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 That(songs).DoesNotHaveItem("I Me Mine").AtIndex(1);
await That(songs).DoesNotHaveItem("Two of Us").AtIndex(4); // no item at index 4
await That(songs).DoesNotHaveItem().Matching(it => it.StartsWith("I Me")).AtIndex(1);
await That(songs).DoesNotHaveItemThat(it => it.StartsWith("I Me")).AtIndex(1);