dart-matcher-best-practices

Bonnes pratiques pour l'utilisation de `expect` et `package:matcher`. Axées sur des assertions lisibles, le choix approprié des matchers et l'évitement des pièges courants.

npx skills add https://github.com/flutter/skills --skill dart-matcher-best-practices

Dart Matcher Bonnes Pratiques

Quand utiliser cette skill

Utilisez cette skill quand :

  • Vous écrivez des assertions avec expect et package:matcher.
  • Vous migrez des vérifications manuelles héritées vers des matchers plus propres.
  • Vous debuggez des échecs de test déroutants.

Découverte

Pour trouver des candidates à 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 des 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 dans des maps 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).
  • isEmpty / isNotEmpty :

    • Préférez expect(list, isEmpty) à expect(list.isEmpty, true).
    • Préférez expect(list, isNotEmpty) à expect(list.isNotEmpty, true).
  • 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 à vérifier expect(map[key], value) ou expect(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 de chaîner des contraintes avec .having().
  • TypeMatcher<T> :

    • Préférez quand vous définissez des matchers réutilisables au niveau du fichier.
    • Utilisez const : const isMyType = TypeMatcher<MyType>();
    • Le chaînage .having() fonctionne aussi ici, mais le matcher résultant n'est pas const.

3. Propriétés d'Objet (having)

Utilisez .having() sur isA<T>() ou d'autres TypeMatchers pour vérifier les propriétés.

  • Noms Descriptifs : Utilisez des noms de paramètres significatifs dans la closure (p. ex., (e) => e.message) au lieu de noms génériques comme p0 pour 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 qu'une future se termine et vérifiez sa valeur.
    • Préférez await expectLater(...) pour s'assurer que la future se termine avant que le test ne continue.
    • await expectLater(future, completion(equals(42))).
  • throwsA(matcher) :

    • Vérifiez qu'une future ou une fonction lance une exception.
    • await expectLater(future, throwsA(isA<StateError>())).
    • expect(() => function(), throwsA(isA<ArgumentError>())) (une fonction synchrone qui lance est correcte avec expect).

5. Utilisation de expectLater

Utilisez await expectLater(...) quand vous testez un comportement asynchrone pour assurer un séquençage correct.

// BON : Attend que la future se termine avant de vérifier les effets de bord
await expectLater(future, completion(equals(42)));
expect(sideEffectState, equals('done'));

// MAUVAIS : La vérification de l'effet de bord peut s'exécuter avant que la future se termine
expect(future, completion(equals(42)));
expect(sideEffectState, equals('done')); // Condition de course !

Principes

  1. Échecs Lisibles : Choisissez des matchers qui produisent des messages d'erreur clairs.
  2. Évitez la Logique Manuelle : N'utilisez pas d'instructions if ou de boucles for pour les assertions ; laissez les matchers s'en charger.
  3. Matchers Spécifiques : Utilisez le matcher le plus spécifique disponible (p. ex., containsPair pour les maps au lieu de vérifier les clés manuellement).

Skills Connexes

  • dart-test-fundamentals : Concepts principaux pour structurer les tests, les cycles de vie et la configuration.
  • dart-checks-migration : Utilisez cette skill si vous migrez des tests de package:matcher vers le moderne package:checks.

Skills similaires