dbt Analytics Engineering study materials
dbt Analytics Engineering study resources

dbt Analytics Engineering: Sources, Tests, and Data Quality

dbt Analytics Engineering · Work through your exam, one topic at a time.

All guide sections

Sources, Tests, and Data Quality

This domain examines how you declare raw data, measure freshness, and encode assumptions as tests. The exam focuses on what dbt actually executes: freshness queries against sources and test queries that return failing rows.

Declaring sources and freshness

Sources are declared in YAML with a source name, database, schema, and tables. Each table can override its identifier. Freshness uses a timestamp column named by loaded_at_field, or a custom query on some adapters, and compares the maximum loaded timestamp with the current time. warn_after and error_after thresholds produce warnings or errors when run with dbt source freshness. Freshness is not a substitute for uniqueness or referential-integrity tests.

Generic and singular tests

Built-in generic tests are unique, not_null, accepted_values, and relationships. They are configured in YAML, can be scoped with where, and can be set to severity: warn or error. The relationships test checks that values in one column exist in a column of another relation, using to: and field:. Singular tests are SQL files that return failing rows; an empty result passes. Custom generic tests are parameterized Jinja macros. store_failures: true writes failing rows to an audit schema for investigation.

Execution behavior

dbt test runs tests after models exist. dbt build interleaves models, tests, seeds, and snapshots in DAG order; a failing test skips downstream nodes. Tests on sources use the source: selector syntax, while model tests use ref() or model names in selection.

Worked example

An orders source has loaded_at_field: _loaded_at, with warn_after: {count: 12, period: hour} and error_after: {count: 24, period: hour}. The order_id column gets unique and not_null; status gets accepted_values for a fixed list; customer_id gets a relationships test to customers. Freshness catches a stalled ingestion pipeline, while the tests catch duplicate keys, nulls, unexpected statuses, and orphaned customers. Together they cover different failure modes.

Traps that cost marks

Freshness cannot run without a timestamp field or configured query. Reversing to and field in a relationships test checks the wrong direction. severity: warn does not fail the job. not_null does not catch empty strings. store_failures requires a configured audit schema and adds storage. Testing a source with ref() instead of source() produces a parse error.