首页/数据/数据工程与 ETL 速查/dbt 自定义测试与严重级别

dbt 自定义测试与严重级别

除通用测试外,dbt 支持在 tests 目录写单条 SQL 作为自定义测试:查询返回任何行即失败;结合 config 的 severity 与 warn_if、error_if 阈值,可把不同严重度的校验分开处理。

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
声明位置模型 YAMLtests 目录下 .sql
判定内置逻辑,失败即报错返回行数大于 0 即失败
适用单列唯一、非空、枚举、外键跨字段、跨表、业务规则
复用性高,可批量声明中等,按文件复用
把基数类校验(行数骤降、均值波动)设为 warn,把键完整性问题(主键重复、非空约束)设为 error,可以让流水线只在真正严重时中断。
warning 级别长期无人处理会逐渐被忽略:要么安排责任人定期清理告警列表,要么把不再有效的测试直接删除,不要让它们长期挂着。
运行范围要用 --select 限定到变更的模型与测试,全量 dbt test 在模型多、数据量大的项目里耗时很长,很难放进每次发布的卡点。
新写的测试先在样本分区上跑一次,确认它能抓到人为构造的违规数据再合入主干,避免上线后才发现 SQL 写错、测试永远通过。

易错点

  • 自定义测试写成返回聚合结果(如 select count(*)),失败时看不出具体哪一行有问题
  • 用 where 限定分区时忘了参数化,硬编码日期导致历史分区长期不被校验
  • warning 级别测试长期无人处理被忽略,真出问题时没有区分高低优先级
  • 对全量历史跑 dbt test 作为发布卡点,发布耗时从几分钟涨到几十分钟,卡点最终被绕过

数据来源与参考

  • dbt 官方文档:Singular Tests 与 severity 配置
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌