Assertions in Dart and Flutter tests: collection matchers
This is the part of the ultimate cheat sheet dedicated to:
- collection matchers,
- string matchers,
- iterable matchers,
- map matchers.
In this series:
- expect and matcher
- equality matchers
- type and error matchers
- collection matchers
- numeric and comparable matchers
- universal and custom matchers
- matcher operators
- asynchronous expect and matchers
- Flutter widget matchers
- accessibility matchers
- golden matchers
- mock invocations and parameters
Collection matchers
By βcollectionβ I mean String
, Iterable
, and Map
.
Size matchers
The pair of isEmpty
and isNotEmpty
matchers call respective .isEmpty
or .isNotEmpty
getters on a result
, and expect them to return true
:
test('expect: isEmpty β
', () {
final result = [];
expect(result, isEmpty);
});
test('expect: isEmpty β', () {
final result = '0';
expect(result, isEmpty);
});
test('expect: isNotEmpty β
', () {
final result = {0: '0'};
expect(result, isNotEmpty);
});
When used with the type that does not have isEmpty
or isNotEmpty
methods:
test('expect: isEmpty β', () {
final result = 0;
expect(result, isNotEmpty);
});
isEmpty
and isNotEmpty
matchers fail the test with the following output:
Expected: non-empty
Actual: <0>
NoSuchMethodError: Class 'int' has no instance getter 'isNotEmpty'.
Receiver: 0
Tried calling: isNotEmpty
The hasLength
matcher follows the same principle and calls .length
getter on the passed value:
test('expect: hasLength β
', () {
final result = '0';
expect(result, hasLength(1));
});
When the value does not have a .length
getter:
test('expect: hasLength β', () {
final result = 0;
expect(result, hasLength(1));
});
the test fails:
Expected: an object with length of <1>
Actual: <0>
Which: has no length property
Content matchers
The contains
matcher has different logic depending on the value it is applied to.
For a String
it means substring matching:
test('expect: contains β
', () {
final result = 'result';
expect(result, contains('res'));
});
For a Map
it means the map has the key:
test('expect: contains β
', () {
final result = {0: Result(0)};
expect(result, contains(0));
});
And for Iterable
it means there is an element matching the matcher that is passed inside contains
matcher. In this test first a predicate
matcher is used, and then an implicit equals
:
test('expect: contains β
', () {
final result = [Result(0), Result(1)];
expect(result, contains(predicate<Result>((r) => r.value == 0)));
expect(result, contains(Result(1)));
});
The isIn
matcher is the opposite to the contains
matcher:
test('expect: isIn β
', () {
final result = 'res';
expect(result, isIn('result'));
});
test('expect: isIn β
', () {
final result = Result(0);
expect(result, isIn([Result(0), Result(1)]));
});
String matchers
In addition to the collection matchers above, that work for String
, there is a couple of matchers more.
Content matchers
startsWith
, endsWith
matchers check String
content along the edges:
test('expect: startsWith β
', () {
final result = 'result';
expect(result, startsWith('res'));
});
test('expect: endsWith β
', () {
final result = 'result';
expect(result, endsWith('ult'));
});
matches
The matches
matcher can either accept another String
:
test('expect: matches β
', () {
final result = 'result';
expect(result, matches('esul'));
});
or a RegExp
:
test('expect: matches β
', () {
final result = 'result';
expect(result, matches(RegExp('r[a-z]{4}t')));
});
Iterable matchers
In addition to the collection matchers above that work for List
and Set
, there are a few more matchers.
every & any
Matchers everyElement
and anyElement
verify that all or some elements satisfy a matcher or are equal to a value they accepted as a parameter:
test('expect: everyElement β
', () {
final result = [Result(0), Result(1)];
expect(result, everyElement(isResult));
});
test('expect: anyElement β
', () {
final result = {0, 1};
expect(result, anyElement(0));
});
Content matchers
Matchers containsAll
and containsAllInOrder
verify that the Iterable
passed as a parameter is a subset of the actual Iterable
, optionally verifying itemsβ order:
test('expect: containsAll β
', () {
final result = [Result(0), Result(1), Result(2)];
expect(result, containsAll([Result(1), Result(0)]));
});
test('expect: containsAllInOrder β
', () {
final result = {0, 1, 2};
expect(result, containsAllInOrder({0, 1}));
});
The actual Iterable
can have additional elements.
Matchers orderedEquals
and unorderedEquals
check that the actual Iterable
is of the same length and contains the same elements as the passed Iterable
, optionally verifying itemsβ order:
test('expect: orderedEquals β
', () {
final result = [Result(0), Result(1)];
expect(result, orderedEquals([Result(0), Result(1)]));
});
test('expect: unorderedEquals β
', () {
final result = {0, 1};
expect(result, unorderedEquals({1, 0}));
});
Map matchers
In addition to collection matchers that work for Map
, there are just a couple more.
containsValue
The containsValue
matcher checks if the actualβs .containsValue()
method returns true
:
test('expect: containsValue β
', () {
final result = {0: Result(0)};
expect(result, containsValue(Result(0)));
});
containsPair
The containsPair
matcher checks both pairβs key and value, where value can be another matcher:
test('expect: containsPair β
', () {
final result = {0: Result(0)};
expect(result, containsPair(0, isResult));
expect(result, containsPair(0, Result(0)));
});
Originally published at Invertase blog. Check out their awesome Authors Program!
Hi! ππ» Iβm Anna, Google Developer Expert in Flutter from Ukraine πΊπ¦ Follow me on Twitter, GitHub, YouTube, Medium to get notifications about my latest work.
Itβs early 2023, and we in Ukraine are still fighting against russians committing genocide on our lands. If you find this content useful and have a coin to spare, support us with your donations. Stand with Ukraine!