dart-matcher-best-practices
Original:🇺🇸 English
Translated
Best practices for using `expect` and `package:matcher`. Focuses on readable assertions, proper matcher selection, and avoiding common pitfalls.
11installs
Sourcekevmoo/dash_skills
Added on
NPX Install
npx skill4agent add kevmoo/dash_skills dart-matcher-best-practicesTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Dart Matcher Best Practices
When to use this skill
Use this skill when:
- Writing assertions using and
expect.package:matcher - Migrating legacy manual checks to cleaner matchers.
- Debugging confusing test failures.
Core Matchers
1. Collections (hasLength
, contains
, isEmpty
, unorderedEquals
, containsPair
)
hasLengthcontainsisEmptyunorderedEqualscontainsPair-
:
hasLength(n)- Prefer over
expect(list, hasLength(n)).expect(list.length, n) - Gives better error messages on failure (shows actual list content).
- Prefer
-
/
isEmpty:isNotEmpty- Prefer over
expect(list, isEmpty).expect(list.isEmpty, true) - Prefer over
expect(list, isNotEmpty).expect(list.isNotEmpty, true)
- Prefer
-
:
contains(item)- Verify existence without manual iteration.
- Prefer over .
expect(list.contains(item), true)
-
:
unorderedEquals(items)- Verify contents regardless of order.
- Prefer over .
expect(list, containsAll(items))
-
:
containsPair(key, value)- Verify a map contains a specific key-value pair.
- Prefer over checking or
expect(map[key], value).expect(map.containsKey(key), true)
2. Type Checks (isA<T>
and TypeMatcher<T>
)
isA<T>TypeMatcher<T>-
:
isA<T>()- Prefer for inline assertions: .
expect(obj, isA<Type>()) - More concise and readable than .
TypeMatcher<Type>() - Allows chaining constraints using .
.having()
- Prefer for inline assertions:
-
:
TypeMatcher<T>- Prefer when defining top-level reusable matchers.
- Use :
constconst isMyType = TypeMatcher<MyType>(); - Chaining works here too, but the resulting matcher is not
.having().const
3. Object Properties (having
)
havingUse on or other TypeMatchers to check properties.
.having()isA<T>()- Descriptive Names: Use meaningful parameter names in the closure (e.g.,
) instead of generic ones like
(e) => e.messageto improve readability.p0
dart
expect(person, isA<Person>()
.having((p) => p.name, 'name', 'Alice')
.having((p) => p.age, 'age', greaterThan(18)));This provides detailed failure messages indicating exactly which property
failed.
4. Async Assertions
-
:
completion(matcher)- Wait for a future to complete and check its value.
- Prefer to ensure the future completes before the test continues.
await expectLater(...) - .
await expectLater(future, completion(equals(42)))
-
:
throwsA(matcher)- Check that a future or function throws an exception.
- .
await expectLater(future, throwsA(isA<StateError>())) - (synchronous function throwing is fine with
expect(() => function(), throwsA(isA<ArgumentError>()))).expect
5. Using expectLater
expectLaterUse when testing async behavior to ensure proper
sequencing.
await expectLater(...)dart
// GOOD: Waits for future to complete before checking side effects
await expectLater(future, completion(equals(42)));
expect(sideEffectState, equals('done'));
// BAD: Side effect check might run before future completes
expect(future, completion(equals(42)));
expect(sideEffectState, equals('done')); // Race condition!Principles
- Readable Failures: Choose matchers that produce clear error messages.
- Avoid Manual Logic: Don't use statements or
ifloops for assertions; let matchers handle it.for - Specific Matchers: Use the most specific matcher available (e.g.,
for maps instead of checking keys manually).
containsPair
Related Skills
- dart-test-fundamentals: Core concepts for structuring tests, lifecycles, and configuration.
- dart-checks-migration: Use this
skill if you are migrating tests from to modern
package:matcher.package:checks