dbt 自定义测试是什么
dbt 的测试分两类:一类是列级通用测试(unique、not_null、accepted_values、relationships),在模型 YAML 里声明;另一类是在 tests 目录下写的单条 SQL 文件,称为 singular test——约定是这条 SQL 返回任何行即判定失败,所以查询要写成“选出违规行”。配合 config 里的 severity(error 或 warn)以及 warn_if、error_if 阈值表达式,可以把轻微波动与硬性错误分开处理,避免流水线被无关紧要的偏差频繁打断。
基本信息
| 适用 | dbt 项目(Core 或 Cloud),底层数据库不限 |
|---|---|
| 自定义测试 | tests 目录下的 .sql 文件,返回行即失败 |
| 严重级别 | severity: error 或 warn |
| 阈值 | error_if / warn_if 表达式,如 '> 1000' |
| 作用范围 | 可加 where 条件限定到特定分区 |
典型使用场景
- 跨字段的业务规则校验:支付金额大于订单金额、发货时间早于签收时间
- 行数骤降监控:与基线相比比例过低时告警,但不阻断发布
- 组合键唯一性校验:单列不唯一但组合应唯一时用自定义 SQL
- 分区级校验:只校验当天分区,避免每次全表扫描
- 交付前验收:业务方要求的对账规则固化成 singular test
自定义测试 SQL
自定义测试 SQL
-- tests/assert_pay_amount_non_negative.sql
-- 约定:返回任何行即失败,所以查询选的是违规行
select order_id, pay_amount
from {{ ref('dwd_trade_order_detail_di') }}
where dt = '2026-10-11'
and pay_amount < 0带阈值与级别
带阈值与级别
-- tests/assert_row_count_not_drop.sql
{{ config(severity='warn', error_if='> 1000', warn_if='> 100') }}
select count(1) as bad_rows
from {{ ref('dwd_trade_order_detail_di') }}
where dt = '2026-10-11' and order_id is null两类测试对照
| 项 | 通用测试 | singular test |
|---|---|---|
| 声明位置 | 模型 YAML | tests 目录下 .sql |
| 判定 | 内置逻辑,失败即报错 | 返回行数大于 0 即失败 |
| 适用 | 单列唯一、非空、枚举、外键 | 跨字段、跨表、业务规则 |
| 复用性 | 高,可批量声明 | 中等,按文件复用 |
把基数类校验(行数骤降、均值波动)设为 warn,把键完整性问题(主键重复、非空约束)设为 error,可以让流水线只在真正严重时中断。
warning 级别长期无人处理会逐渐被忽略:要么安排责任人定期清理告警列表,要么把不再有效的测试直接删除,不要让它们长期挂着。
运行范围要用 --select 限定到变更的模型与测试,全量 dbt test 在模型多、数据量大的项目里耗时很长,很难放进每次发布的卡点。
新写的测试先在样本分区上跑一次,确认它能抓到人为构造的违规数据再合入主干,避免上线后才发现 SQL 写错、测试永远通过。