ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Tests génériques de dbt-utils

Référence complète pour les tests génériques dbt-utils : syntaxe YAML, le changement de clé arguments: dans Fusion, le support group_by_columns et quand utiliser chaque test.

Planté
dbttestingdata quality

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__currency

Si 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__currency

Utilisez-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 NULLstatus = '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: true

Vous 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: 24

Ce 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

TestCe qu’il valide
unique_combination_of_columnsAucune combinaison répétée des colonnes spécifiées
accepted_rangeLes valeurs numériques se situent dans les bornes min/max
expression_is_trueUne expression SQL arbitraire est vraie pour chaque ligne
recencyLa valeur la plus récente dans une colonne de dates se situe dans N dateparts
at_least_oneAu moins une valeur non-null existe dans la colonne
not_constantLes valeurs varient — toutes les lignes n’ont pas la même valeur
not_null_proportionLe taux de null ne dépasse pas un seuil (ex. at_least: 0.95)
relationships_whereIntégrité référentielle filtrée avec une clause WHERE
mutually_exclusive_rangesLes plages de dates/nombres n’ont pas de chevauchements (les deux bornes doivent être NOT NULL)
sequential_valuesUne colonne de séquence n’a pas de lacunes
equal_rowcountDeux relations ont le même nombre de lignes
fewer_rows_thanLa relation A a strictement moins de lignes que la relation B
equalityComparaison complète de modèles (avec precision optionnel pour les colonnes numériques)
not_accepted_valuesInverse de accepted_values — les valeurs ne sont pas dans la liste spécifiée
not_empty_stringLes chaînes ne sont pas vides (avec l’option trim_whitespace)
cardinality_equalityDeux 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.95

mutually_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__processor

Cela 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.