Cet article fait partie de notre guide complet sur dbt.
Tests et qualité des données avec dbt
Découvrez comment implémenter une stratégie de testing robuste pour garantir la fiabilité et la qualité de vos transformations de données.
La qualité des données est fondamentale pour des décisions business fiables. dbt transforme le testing de données de corvée manuelle en processus automatisé et intégré.
Chaque test dbt est une assertion SQL simple : si la requête retourne des lignes, le test échoue. Cette approche permet de valider toutes les hypothèses sur vos données de manière systématique.
Les 4 types de tests dbt
Tests génériques
Tests préconfigurés : unique, not_null, accepted_values, relationships
Tests personnalisés
Logique métier complexe dans des fichiers SQL dédiés
Tests unitaires
Validation isolée avec données mockées (dbt 1.8+)
Packages de tests
dbt-utils, dbt-expectations pour tests avancés
Tests génériques : les fondamentaux
Les tests génériques sont les 4 validations essentielles prêtes à l'emploi dans dbt. Ils couvrent 80% des cas d'usage de validation de données.
🔑 unique
Validation : Aucune valeur dupliquée dans une colonne
Cas d'usage : Clés primaires, identifiants uniques, emails
# schema.yml
models:
- name: customers
columns:
- name: customer_id
tests:
- unique
✅ not_null
Validation : Aucune valeur nulle dans une colonne
Cas d'usage : Champs obligatoires, clés étrangères critiques
# schema.yml
models:
- name: orders
columns:
- name: order_date
tests:
- not_null
📋 accepted_values
Validation : Valeurs limitées à une liste prédéfinie
Cas d'usage : Statuts, catégories, énumérations
# schema.yml
models:
- name: orders
columns:
- name: status
tests:
- accepted_values:
values: ['placed', 'shipped', 'completed', 'returned']
🔗 relationships
Validation : Intégrité référentielle entre tables
Cas d'usage : Clés étrangères, relations parent-enfant
# schema.yml
models:
- name: orders
columns:
- name: customer_id
tests:
- relationships:
to: ref('customers')
field: customer_id
Exemple complet : Table orders
# models/schema.yml
version: 2
models:
- name: orders
description: "Table des commandes clients"
columns:
- name: order_id
description: "Identifiant unique de commande"
tests:
- unique
- not_null
- name: customer_id
description: "Référence vers le client"
tests:
- not_null
- relationships:
to: ref('customers')
field: customer_id
- name: status
description: "Statut de la commande"
tests:
- not_null
- accepted_values:
values: ['placed', 'shipped', 'completed', 'returned']
- name: order_date
description: "Date de création de la commande"
tests:
- not_null
Tests personnalisés : logique métier complexe
Quand les tests génériques ne suffisent plus, créez vos propres validations SQL dans le répertoire tests/
.
Principe
- • Fichier
.sql
danstests/
- • Requête SELECT qui retourne les lignes problématiques
- • 0 ligne = test réussi
- • > 0 lignes = test échoué
Cas d'usage
- • Règles métier spécifiques
- • Validations sur plusieurs colonnes
- • Cohérence entre tables
- • Calculs et agrégations complexes
Exemple 1 : Montants négatifs interdits
Objectif : Vérifier qu'aucune commande n'a un montant négatif
-- tests/assert_positive_order_amount.sql
-- Ce test échoue s'il trouve des montants négatifs
select
order_id,
amount
from
{{ ref('orders') }}
where
amount < 0
Exemple 2 : Cohérence temporelle
Objectif : La date de livraison doit être postérieure à la date de commande
-- tests/assert_delivery_after_order.sql
-- Ce test échoue si delivery_date < order_date
select
order_id,
order_date,
delivery_date
from
{{ ref('orders') }}
where
delivery_date < order_date
and delivery_date is not null
Exemple 3 : Cohérence inter-tables
Objectif : Le total des lignes de commande doit correspondre au montant de la commande
-- tests/assert_order_totals_match.sql
-- Vérifie la cohérence entre orders et order_items
with order_calculated_totals as (
select
order_id,
sum(quantity * unit_price) as calculated_total
from {{ ref('order_items') }}
group by order_id
),
order_discrepancies as (
select
o.order_id,
o.total_amount as order_total,
oct.calculated_total,
abs(o.total_amount - oct.calculated_total) as difference
from {{ ref('orders') }} o
join order_calculated_totals oct
on o.order_id = oct.order_id
where abs(o.total_amount - oct.calculated_total) > 0.01
)
select * from order_discrepancies
Tests unitaires : validation isolée (dbt 1.8+)
Nouveauté dbt 1.8 : Les tests unitaires permettent de tester la logique de transformation avec des données fictives, sans interroger votre entrepôt.
Plus rapides, moins coûteux, plus ciblés sur la logique pure.
Avantages
- ✓ Rapidité - Pas de requête sur l'entrepôt
- ✓ Coût réduit - Aucune consommation compute
- ✓ Isolation - Test de la logique pure
- ✓ Contrôle - Données d'entrée maîtrisées
Cas d'usage
- • Validation des calculs complexes
- • Test des macros personnalisées
- • Logique de transformation métier
- • Cas limite et edge cases
Exemple : Test d'un modèle de calcul de prix final
Testons un modèle qui applique une remise sur le prix de base.
Le modèle à tester
-- models/final_price.sql
select
product_id,
price,
discount,
case
when discount > price then 0
else price - discount
end as final_price
from {{ ref('base_products') }}
Le test unitaire
# models/schema.yml
models:
- name: final_price
tests:
- unit:
given:
- input: ref('base_products')
rows:
- {product_id: 1, price: 100, discount: 10}
- {product_id: 2, price: 50, discount: 60}
expected:
rows:
- {product_id: 1, final_price: 90}
- {product_id: 2, final_price: 0}
Explication : Le test vérifie que le produit 1 (100-10=90) et le produit 2 (remise > prix = 0) sont calculés correctement selon notre logique métier.
Packages de tests : étendre les capacités
La communauté dbt a développé des packages riches en tests avancés pour couvrir des cas d'usage complexes.
🛠️ dbt-utils
Le package de référence avec des macros et tests essentiels.
Tests populaires :
- •
equal_rowcount
- Compare le nombre de lignes entre tables - •
fewer_rows_than
- Vérifie qu'une table a moins de lignes qu'une autre - •
equality
- Compare deux requêtes complètement - •
recency
- Vérifie la fraîcheur des données
# Installation
packages:
- package: dbt-labs/dbt_utils
version: 1.1.1
🎯 dbt-expectations
Inspiré de Great Expectations, collection très riche de validations.
Tests avancés :
- •
expect_column_values_to_be_between
- Plages de valeurs - •
expect_column_values_to_match_regex
- Expressions régulières - •
expect_table_row_count_to_be_between
- Contrôle volume - •
expect_column_pair_values_to_be_equal
- Comparaison colonnes
# Installation
packages:
- package: calogica/dbt_expectations
version: 0.10.0
Exemple dbt-utils : Comparaison de tables
# models/schema.yml
models:
- name: orders_transformed
tests:
# Vérifier que le nombre de commandes n'a pas changé après transformation
- dbt_utils.equal_rowcount:
compare_model: ref('orders_source')
# Vérifier la fraîcheur des données (max 1 jour)
- dbt_utils.recency:
datepart: day
field: created_at
interval: 1
Exemple dbt-expectations : Validations avancées
# models/schema.yml
models:
- name: customers
columns:
- name: age
tests:
# Âge entre 0 et 120 ans
- dbt_expectations.expect_column_values_to_be_between:
min_value: 0
max_value: 120
- name: email
tests:
# Format email valide
- dbt_expectations.expect_column_values_to_match_regex:
regex: "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$"
Exécution et workflow de testing
dbt test
Exécute tous les tests du projet
dbt test
Test sélectif
Teste un modèle spécifique
dbt test --select orders
dbt build
Build + tests en une commande
dbt build
Stratégie de testing recommandée
Phase de développement
- 1 Tests génériques sur chaque modèle (unique, not_null)
- 2 Tests unitaires pour la logique complexe
- 3
dbt test --select model_name
à chaque modification
Phase de production
- 1 Tests personnalisés pour les règles métier
- 2 Packages avancés (dbt-expectations) pour la surveillance
- 3
dbt build
dans les pipelines CI/CD
Meilleures pratiques
✅ À faire
- • Tester systematiquement les clés primaires (unique + not_null)
- • Implémenter des tests sur les colonnes critiques métier
- • Utiliser des tests personnalisés pour la logique complexe
- • Intégrer
dbt build
dans vos pipelines CI/CD - • Documenter le contexte métier de chaque test
- • Commencer simple, enrichir progressivement
💡 Conseils avancés
- • Utilisez les tests unitaires pour les cas limite
- • Groupez les tests par criticité (tags)
- • Surveillez les performances de vos tests
- • Créez des macros pour les validations récurrentes
❌ À éviter
- • Négliger les tests sur les modèles downstream critiques
- • Créer des tests trop lents qui bloquent le développement
- • Ignorer les échecs de test sans investigation
- • Dupliquer la logique entre tests génériques et personnalisés
- • Oublier de tester les transformations de données sensibles
⚠️ Attention
- • Les tests consomment des ressources compute
- • Tests trop stricts = faux positifs fréquents
- • Équilibrer couverture et maintenance
- • Adapter la stratégie selon l'environnement