Tests, documentación y lineage
Un data test es un SELECT que busca filas que contradicen una aserción. Cero filas → pasa. unique busca duplicados; not_null busca nulos. No es un CHECK del warehouse: dbt no crea constraints. Detecta regresiones cuando el SQL o los datos cambian.
La clave YAML actual es data_tests. tests sigue existiendo como alias. Los unit tests son otra cosa (YAML bajo model-paths); no van en tests/.
Documentación: data tests, propiedad data_tests, describe your project.
Genéricos: los cuatro de serie
Un test genérico es una consulta parametrizada ({% test %}) que reutilizas en YAML. dbt trae cuatro:
| Test | Aserción |
|---|---|
unique | La columna no tiene duplicados. |
not_null | La columna no tiene NULL. |
accepted_values | Los no nulos están en una lista. |
relationships | Cada valor (no nulo) existe en otra relación. |
models/marts/schema.yml:
models:
- name: fct_orders
description: Un pedido válido. Grain: order_id.
columns:
- name: order_id
description: Clave del pedido.
data_tests:
- unique
- not_null
- name: status
data_tests:
- accepted_values:
arguments:
values: ['placed', 'shipped', 'completed', 'returned']
- name: customer_id
data_tests:
- relationships:
arguments:
to: ref('stg_customers')
field: customer_idarguments anida los parámetros del test (dbt 1.10.5+). Versiones anteriores ponían values / to / field en el primer nivel.
relationships ignora NULL en el hijo, igual que una FK. Si el nulo también es error, añade not_null.
Los mismos tests se cuelgan de sources, seeds y snapshots. Una source sin unique + not_null en la clave deja que el staging herede basura.
dbt test
dbt test --select fct_orders
dbt test --select "source:*"
dbt build --select fct_orders+dbt test solo corre tests. dbt build construye el recurso y después testea. En CI suele interesar build sobre el subgrafo tocado.
Singulares: una query, un caso
Cuando la aserción no cabe en un genérico, un fichero en tests/ es el test. El nombre es el del fichero. Devuelve las filas que fallan. Sin punto y coma final.
tests/assert_fct_orders_amount_positive.sql:
select
order_id,
amount
from {{ ref('fct_orders') }}
where amount <= 0No declares tests singulares como si fueran genéricos en el YAML del modelo: dbt los recoge por vivir en test-paths.
Si copias la misma forma cambiando solo la columna, ya no es singular: escribe un genérico o instala uno de un paquete (dbt_utils, etc.).
Documentación
description en YAML no es un comentario: entra en el sitio de docs y en el catálogo. Un modelo sin descripción sigue compilando; el lineage se lee peor.
sources:
- name: raw
description: Réplica ELT de la app. dbt no la escribe.
tables:
- name: orders
description: Un registro por pedido, incluidos cancelados.
columns:
- name: id
description: PK de la tabla origen.dbt docs generate
dbt docs servegenerate escribe el manifiesto y el catálogo estático en target/. serve es local. En la plataforma de dbt el mismo grafo aparece como Catalog; el contrato del proyecto (YAML + ref/source) es el mismo.
Documenta el grain y lo que el modelo no es (“no incluye pedidos a 0”). Eso evita que BI reinterprete la tabla.
Lineage
El lineage no se dibuja a mano. Sale de source() y ref():
source:raw.orders ──► stg_orders ──► fct_orders ──► (BI / exposiciones)
source:raw.customers ──► stg_customers ─┘Si un mart lee raw.public.orders en SQL plano, desaparece del grafo. Los docs mostrarán un nodo huérfano o un origen opaco.
Selectores que aprovechan el grafo:
dbt run --select stg_orders+ # el modelo y downstream
dbt test --select +fct_orders # upstream de fct_orders, tests incluidos según recurso
dbt ls --select source:raw.orders+Errores comunes
- Tratar
dbt testcomo substituto de constraints del warehouse o de contratos de calidad en origen. - Tests solo en marts: el fallo aparece tarde y en un JOIN ilegible.
accepted_valuessinquote: falsesobre enteros/booleanos.- Unit tests en
tests/: van junto a los modelos, no entest-paths. - Descripciones copiadas (“tabla de pedidos”) que no dicen el grain.
Buenas prácticas
- Empieza por
unique+not_nullen claves de sources y staging. relationshipsentre fact y dimensiones que el mart asume.severity: warnpara aserciones que aún no puedes hacer fallar el job; no para olvidarte del test.dbt builden CI sobre el estado modificado, norunsin tests.- Mira el SQL compilado del test en
target/compiled/cuando falle: es unSELECTmás.
Ejercicio
- Añade
uniqueynot_nullaorder_idenstg_ordersy en la sourceraw.orders. - Relaciona
fct_orders.customer_idconstg_customers.customer_id. - Escribe un test singular que falle si
sum(amount)por pedido es negativa. - Genera docs y sigue el camino
raw.orders→fct_orders.
Siguiente paso
Snapshots y seeds: CSV versionados y SCD tipo 2 sobre tablas que se pisan.
