ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Organisation des fichiers de tests unitaires dbt

Où placer les fichiers de tests unitaires dbt, comment nommer les tests de manière cohérente et le pattern de co-localisation avec _unit_tests.yml.

Planté
dbttesting

L’emplacement des fichiers de tests affecte la découvrabilité et la maintenabilité. Les tests placés dans un répertoire séparé sont souvent ignorés lors des revues ou se déconnectent des modèles qu’ils couvrent.

Co-localiser les tests avec les modèles

Le pattern recommandé : placer les tests unitaires dans un fichier _unit_tests.yml à l’intérieur du même répertoire que les modèles qu’ils testent.

models/
├── base/
│ ├── crm/
│ │ ├── base__crm__customers.sql
│ │ └── _crm__models.yml
│ └── shopify/
│ ├── base__shopify__orders.sql
│ └── _shopify__models.yml
├── intermediate/
│ ├── int__customers_enriched.sql
│ └── _intermediate__models.yml
├── marts/
│ ├── core/
│ │ ├── mrt__core__customers.sql
│ │ ├── _core__models.yml
│ │ └── _unit_tests.yml # Tests unitaires pour les marts core
│ └── finance/
│ ├── mrt__finance__orders.sql
│ ├── _finance__models.yml
│ └── _unit_tests.yml # Tests unitaires pour les marts finance
tests/
└── fixtures/
├── customer_fixture.csv
└── large_order_dataset.csv

Cela suit le même principe de co-localisation que les fichiers YAML des modèles. Lorsque vous ouvrez le répertoire d’un modèle, vous voyez son SQL, sa définition de schéma et ses tests unitaires ensemble. Pas besoin de chercher dans des répertoires de tests séparés pour trouver les tests qui existent pour un modèle.

La convention de nommage _unit_tests.yml reflète le pattern existant _models.yml — le préfixe underscore le trie en haut du listing du répertoire, le rendant immédiatement visible.

Pourquoi ne pas mettre les tests unitaires dans le YAML des modèles ?

Vous pouvez techniquement mettre des blocs unit_tests: dans le même fichier YAML que vos définitions de modèles. Pour les projets avec peu de tests unitaires, cela fonctionne bien. Mais à mesure que votre suite de tests grandit, le fichier YAML du modèle enfle. Un fichier qui mélange configuration du modèle, documentation des colonnes, tests de données génériques et tests unitaires devient difficile à naviguer.

Séparer les tests unitaires dans leur propre fichier garde chaque fichier YAML focalisé :

  • _core__models.yml — configuration du modèle, descriptions des colonnes, tests de données génériques
  • _unit_tests.yml — tests unitaires avec leurs entrées mockées et sorties attendues

Cette séparation réduit aussi les conflits de merge. Les tests unitaires changent fréquemment (au fur et à mesure que vous ajoutez des cas limites ou mettez à jour des fixtures), alors que les configurations des modèles changent moins souvent. Des fichiers séparés signifient des historiques de modification séparés.

Fixtures externes

Pour les données de test réutilisées dans plusieurs tests ou trop volumineuses pour un YAML inline, utilisez des fichiers CSV de fixtures externes dans tests/fixtures/ :

tests/
└── fixtures/
├── customer_fixture.csv
└── large_order_dataset.csv

Référencez-les dans vos tests unitaires avec la clé fixture :

unit_tests:
- name: test_large_order_processing
model: mrt__finance__orders
given:
- input: ref('base__shopify__orders')
format: csv
fixture: large_order_dataset
expect:
rows:
- {order_id: 1, total: 5000.00}

Les fixtures externes ont du sens lorsque :

  • Le même jeu de données est nécessaire dans plusieurs tests répartis dans différents répertoires
  • Les données de test ont de nombreuses colonnes et rendraient le fichier YAML ingérable
  • Vous souhaitez que des non-ingénieurs (comme des analystes ou des experts du domaine) puissent revoir ou contribuer aux données de test dans un format tableur familier

Le compromis est l’indirection. Quelqu’un lisant le YAML du test unitaire doit ouvrir un fichier séparé pour voir les données d’entrée réelles. Pour la plupart des tests, le format dict inline est préférable car il garde tout visible en un seul endroit.

Conventions de nommage

Des noms de tests cohérents rendent les échecs immédiatement compréhensibles dans les logs CI. Adoptez un pattern :

unit_tests:
# Pattern : test_<nom_court_modele>_<scenario>
- name: test_mrt_core_customers_email_validation
- name: test_mrt_core_customers_null_handling
- name: test_mrt_finance_orders_discount_calculation
- name: test_mrt_finance_orders_zero_quantity_edge_case

Le nom court du modèle évite la convention double underscore complète (qui rendrait les noms excessivement longs) mais conserve suffisamment de contexte pour identifier le modèle. Le suffixe de scénario décrit ce que le test vérifie.

Lorsqu’un test échoue en CI, vous voyez :

FAIL test_mrt_finance_orders_discount_calculation

Cela vous indique immédiatement : c’est le mart des commandes finance, le calcul de la remise est cassé. Pas besoin de chercher à quel modèle appartient le test.

Certaines équipes préfèrent des noms plus courts comme test_discount_calc et s’appuient sur l’emplacement du fichier pour le contexte. Cela fonctionne dans les petits projets mais s’effondre lorsque vous avez des centaines de tests sur des dizaines de modèles — test_null_handling ne vous dit rien si vous ne pouvez pas voir de quel fichier il provient.

Où se concentrent les tests unitaires

En pratique, les tests unitaires se concentrent dans la couche mart. La stratégie de tests par couche explique pourquoi : les marts contiennent la logique métier complexe — segmentation client, calculs de revenus, dérivations de métriques — qui justifie la surcharge des tests à entrées mockées.

Les modèles base ont rarement besoin de tests unitaires (leur logique est mécanique : renommer, caster, filtrer). Les modèles intermediate en ont parfois besoin (pour une logique de jointure ou d’agrégation complexe). Les marts sont là où vivent les règles métier, et les règles métier sont là où se cachent les bugs.

Cela signifie que vos fichiers _unit_tests.yml apparaîtront principalement dans les répertoires models/marts/*/. C’est attendu. Si vous trouvez que vous écrivez de nombreux tests unitaires pour les modèles base, vous avez peut-être de la logique métier dans la mauvaise couche.

Faire évoluer la suite de tests

À mesure que votre projet grandit, quelques pratiques organisationnelles gardent les choses gérables :

Étiquetez les tests par domaine métier. Ajoutez config: {tags: ["finance"]} ou config: {tags: ["marketing"]} pour que les équipes puissent n’exécuter que leurs tests pendant le développement.

Regroupez les tests liés. Si un seul modèle a 8+ tests unitaires, demandez-vous si certains scénarios pourraient être combinés ou si le modèle lui-même fait trop de choses. Un modèle qui nécessite 8 tests unitaires pourrait bénéficier d’être divisé en modèles plus petits et plus focalisés.

Révisez les fichiers de tests lors des revues de code. Lorsqu’une PR modifie le SQL d’un modèle, vérifiez si _unit_tests.yml a également été mis à jour. Les nouveaux cas limites dans la logique doivent s’accompagner de nouveaux scénarios de test.