Bonnes pratiques Dart Matcher
Quand utiliser cette compétence
Utilisez cette compétence lorsque :
- Vous écrivez des assertions en utilisant
expectetpackage:matcher. - Vous migrez des vérifications manuelles héritées vers des matchers plus propres.
- Vous déboguez des échecs de test confus.
Découverte
Pour trouver des candidats à l'amélioration de l'utilisation des matchers, recherchez des motifs sous-optimaux :
Vérifications de longueur sous-optimales
Recherchez les vérifications de longueur qui devraient utiliser hasLength :
- Regex :
expect\([^,]+.length,\s*
Vérifications booléennes sous-optimales
Recherchez les vérifications sur les propriétés booléennes qui ont des matchers spécifiques :
- Regex :
expect\([^,]+.isEmpty,\s*(true|equals\(true\)) - Regex :
expect\([^,]+.isNotEmpty,\s*(true|equals\(true\)) - Regex :
expect\([^,]+.contains\(.*\),\s*(true|equals\(true\))
Recherches de map sous-optimales
Recherchez les recherches manuelles de map au lieu d'utiliser containsPair :
- Regex :
expect\([^,]+\[.*\],\s*
Matchers principaux
1. Collections (hasLength, contains, isEmpty, unorderedEquals, containsPair)
-
hasLength(n):- Préférez
expect(list, hasLength(n))àexpect(list.length, n). - Donne de meilleurs messages d'erreur en cas d'échec (affiche le contenu réel de la liste).
- Préférez
-
isEmpty/isNotEmpty:- Préférez
expect(list, isEmpty)àexpect(list.isEmpty, true). - Préférez
expect(list, isNotEmpty)àexpect(list.isNotEmpty, true).
- Préférez
-
contains(item):- Vérifiez l'existence sans itération manuelle.
- Préférez à
expect(list.contains(item), true).
-
unorderedEquals(items):- Vérifiez le contenu indépendamment de l'ordre.
- Préférez à
expect(list, containsAll(items)).
-
containsPair(key, value):- Vérifiez qu'une map contient une paire clé-valeur spécifique.
- Préférez à la vérification de
expect(map[key], value)ouexpect(map.containsKey(key), true).
2. Vérifications de type (isA<T> et TypeMatcher<T>)
-
isA<T>():- Préférez pour les assertions en ligne :
expect(obj, isA<Type>()). - Plus concis et lisible que
TypeMatcher<Type>(). - Permet le chaînage des contraintes en utilisant
.having().
- Préférez pour les assertions en ligne :
-
TypeMatcher<T>:- Préférez pour définir des matchers réutilisables au niveau supérieur.
- Utilisez
const:const isMyType = TypeMatcher<MyType>(); - Le chaînage de
.having()fonctionne ici aussi, mais le matcher résultant n'est pasconst.
3. Propriétés d'objet (having)
Utilisez .having() sur isA<T>() ou d'autres TypeMatchers pour vérifier les propriétés.
- Noms explicites : Utilisez des noms de paramètres explicites dans la closure (par exemple,
(e) => e.message) au lieu de noms génériques commep0pour améliorer la lisibilité.
expect(person, isA<Person>()
.having((p) => p.name, 'name', 'Alice')
.having((p) => p.age, 'age', greaterThan(18)));
Cela fournit des messages d'échec détaillés indiquant exactement quelle propriété a échoué.
4. Assertions asynchrones
-
completion(matcher):- Attendez la fin d'une future et vérifiez sa valeur.
- Préférez
await expectLater(...)pour vous assurer que la future se termine avant que le test continue. await expectLater(future, completion(equals(42))).
-
throwsA(matcher):- Vérifiez qu'une future ou une fonction lève une exception.
await expectLater(future, throwsA(isA<StateError>())).expect(() => function(), throwsA(isA<ArgumentError>()))(une fonction synchrone qui lance une exception va bien avecexpect).
5. Utiliser expectLater
Utilisez await expectLater(...) lors du test du comportement asynchrone pour assurer un séquençage approprié.
// BON : Attend que la future se termine avant de vérifier les effets secondaires
await expectLater(future, completion(equals(42)));
expect(sideEffectState, equals('done'));
// MAUVAIS : La vérification des effets secondaires pourrait s'exécuter avant la fin de la future
expect(future, completion(equals(42)));
expect(sideEffectState, equals('done')); // Condition de course !
Principes
- Échecs lisibles : Choisissez les matchers qui produisent des messages d'erreur clairs.
- Évitez la logique manuelle : N'utilisez pas d'instructions
ifou de bouclesforpour les assertions ; laissez les matchers s'en charger. - Matchers spécifiques : Utilisez le matcher le plus spécifique disponible (par exemple,
containsPairpour les maps au lieu de vérifier les clés manuellement).
Compétences associées
- dart-test-fundamentals : Concepts clés pour structurer les tests, les cycles de vie et la configuration.
- dart-checks-migration : Utilisez cette
compétence si vous migrez les tests de
package:matchervers le modernepackage:checks.