dbt-utils inclut une suite de tests génériques qui va bien au-delà des quatre tests intégrés (unique, not_null, accepted_values, relationships). C’est la première extension que la plupart des projets dbt ajoutent, et pour de bonnes raisons — unique_combination_of_columns et expression_is_true à eux seuls couvrent des situations qui se présentent dans presque tous les projets.
Pour la place de ces tests dans l’image globale des tests, voir Taxonomie des tests dbt.
Changement de syntaxe Fusion / dbt Core 1.10.6+
Avant d’utiliser des tests dbt-utils, vérifiez votre version dbt. À partir de dbt Fusion (dbt 2.0) et dbt Core 1.10.6+, les arguments de test doivent être imbriqués sous une clé arguments: en YAML :
# dbt Core < 1.10.6 (syntaxe originale)- dbt_utils.unique_combination_of_columns: combination_of_columns: - revenue__date - revenue__currency
# dbt Fusion / dbt Core 1.10.6+ (nouvelle syntaxe)- dbt_utils.unique_combination_of_columns: arguments: combination_of_columns: - revenue__date - revenue__currencySi vous mettez à niveau dbt et que vos tests commencent à échouer avec des erreurs liées aux arguments, c’est la première chose à vérifier. Les exemples ci-dessous montrent la syntaxe originale — ajoutez le wrapper arguments: si vous êtes sur une version plus récente.
Les tests clés
unique_combination_of_columns
Teste l’unicité composite — qu’aucune combinaison des colonnes spécifiées ne se répète. C’est le test pour tout modèle dont la granularité est définie par plusieurs colonnes :
models: - name: mrt__finance__daily_revenue data_tests: - dbt_utils.unique_combination_of_columns: combination_of_columns: - revenue__date - revenue__currencyUtilisez-le partout où unique sur une seule colonne n’aurait pas de sens. Une table de faits avec une ligne par commande par produit par jour nécessite ce test sur (order__id, product__id, order__date), pas unique sur une colonne individuelle.
expression_is_true
Évalue n’importe quelle expression SQL par ligne. Il échoue si une ligne produit FALSE ou NULL. C’est le couteau suisse pour les assertions qui ne rentrent pas proprement dans d’autres types de tests :
models: - name: mrt__finance__invoices data_tests: - dbt_utils.expression_is_true: expression: "invoice__total_amount >= invoice__tax_amount" where: "invoice__status != 'voided'"Usages courants :
- Validation croisée de colonnes :
end_date >= start_date,quantity > 0 - Vérifications de colonnes calculées :
discount_amount <= subtotal - Vérifications dépendantes du statut :
shipped_at IS NOT NULLoùstatus = 'shipped'
Note de migration depuis v0.x : L’ancien argument condition a été supprimé en v1.0. Utilisez le config natif where à la place (comme montré ci-dessus). Tout YAML de test avec condition: doit être mis à jour.
accepted_range
Valide que les valeurs numériques se trouvent dans des bornes :
columns: - name: order__total_amount data_tests: - dbt_utils.accepted_range: min_value: 0 inclusive: true - name: conversion__rate data_tests: - dbt_utils.accepted_range: min_value: 0 max_value: 1 inclusive: trueVous pouvez spécifier min_value, max_value ou les deux. Le paramètre inclusive contrôle si les bornes sont inclusives (>=/<=) ou exclusives (>/<).
Ce test détecte les valeurs impossibles avant qu’elles ne corrompent les métriques — revenus négatifs, taux de conversion supérieurs à 100 %, durées de session en secondes négatives. Exécutez-le sur toute colonne numérique avec des bornes signifiantes.
recency
Vérifie que les données sont fraîches en s’assurant que la valeur la plus récente dans une colonne de dates se situe dans un intervalle spécifié :
models: - name: base__stripe__charges data_tests: - dbt_utils.recency: datepart: hour field: charge__created_at interval: 24Ce test échoue si la ligne la plus récente dans charge__created_at a plus de 24 heures. Définissez datepart selon la granularité naturelle de vos données.
C’est une vérification de fraîcheur au niveau du modèle, distincte des vérifications de fraîcheur des sources. La fraîcheur des sources (dbt source freshness) vérifie si la source a été chargée récemment. recency vérifie si la sortie du modèle contient des données récentes, ce qui détecte aussi les bugs de transformation qui filtrent accidentellement les lignes récentes.
Référence complète des tests
| Test | Ce qu’il valide |
|---|---|
unique_combination_of_columns | Aucune combinaison répétée des colonnes spécifiées |
accepted_range | Les valeurs numériques se situent dans les bornes min/max |
expression_is_true | Une expression SQL arbitraire est vraie pour chaque ligne |
recency | La valeur la plus récente dans une colonne de dates se situe dans N dateparts |
at_least_one | Au moins une valeur non-null existe dans la colonne |
not_constant | Les valeurs varient — toutes les lignes n’ont pas la même valeur |
not_null_proportion | Le taux de null ne dépasse pas un seuil (ex. at_least: 0.95) |
relationships_where | Intégrité référentielle filtrée avec une clause WHERE |
mutually_exclusive_ranges | Les plages de dates/nombres n’ont pas de chevauchements (les deux bornes doivent être NOT NULL) |
sequential_values | Une colonne de séquence n’a pas de lacunes |
equal_rowcount | Deux relations ont le même nombre de lignes |
fewer_rows_than | La relation A a strictement moins de lignes que la relation B |
equality | Comparaison complète de modèles (avec precision optionnel pour les colonnes numériques) |
not_accepted_values | Inverse de accepted_values — les valeurs ne sont pas dans la liste spécifiée |
not_empty_string | Les chaînes ne sont pas vides (avec l’option trim_whitespace) |
cardinality_equality | Deux colonnes ont le même nombre de valeurs distinctes |
Tests qui méritent une attention particulière
not_null_proportion est utile quand un not_null strict est trop rigide. Une colonne email avec 5 % de nulls peut être acceptable ; 40 % de nulls peut indiquer un pipeline cassé. Définissez un seuil et testez par rapport à celui-ci :
- dbt_utils.not_null_proportion: at_least: 0.95mutually_exclusive_ranges valide qu’une table d’intervalles (plages de dates, paliers de prix, périodes de validité) n’a pas de chevauchements. Un système de facturation qui génère accidentellement deux paliers de prix actifs est une catégorie de bug que ce test détecte directement.
equality compare deux modèles ligne par ligne. C’est le bon outil pour valider qu’un modèle refactorisé produit une sortie identique à son prédécesseur — essentiel pendant les migrations. L’argument precision gère correctement la comparaison de valeurs à virgule flottante plutôt que d’exiger une égalité exacte sur les nombres calculés.
relationships_where est la version filtrée du test intégré relationships. Utilisez-le lorsque l’intégrité référentielle ne s’applique qu’à un sous-ensemble de lignes :
- dbt_utils.relationships_where: to: ref('mrt__core__products') field: product__id from_condition: "order__status != 'cancelled'"group_by_columns
Plusieurs tests supportent un paramètre group_by_columns qui valide la condition du test dans chaque groupe séparément. C’est utile pour la validation segmentée — vérifier la fraîcheur par source de données, ou confirmer que les comptages de lignes correspondent par région :
Tests qui supportent group_by_columns : equal_rowcount, fewer_rows_than, recency, at_least_one, not_constant, sequential_values, not_null_proportion.
- dbt_utils.recency: datepart: hour field: charge__created_at interval: 24 group_by_columns: - payment__processorCela vérifie que chaque valeur distincte de payment__processor a des données récentes, plutôt que de vérifier la table dans son ensemble. Un seul processeur actif masque un processeur inactif sans ce paramètre.