Skip to content

测试

简介

测试是您对dbt项目中的模型和其他资源(例如源、种子和快照)所做的断言。当您运行dbt test时,dbt会告诉您项目中的每个测试是通过还是失败。

通过对生成的结果进行断言,可以使用测试来提高每个模型中SQL的完整性。开箱即用,您可以测试模型中的指定列是否只包含非null值、唯一值或在另一个模型中具有相应值的值(例如,订单customer_id对应于客户模型中的id),以及指定列表中的值。您可以扩展测试以适应特定于组织的业务逻辑,您可以以一个select查询的形式对模型做出的任何断言都可以转化为测试。

与dbt中的几乎所有内容一样,测试都是SQL查询。特别是,它们是select语句,试图获取失败的记录,来反驳你的断言。如果断言一个字段在模型中是唯一的,则测试查询会选择重复列;如果断言字段从不为null,那么测试将查找null。如果测试返回零个失败行,那么它就通过了,并且您的断言已经得到验证。

在dbt中定义测试有两种方法:

  • 单例 测试是以最简单的形式进行测试的: 如果您可以编写返回失败行的SQL查询,则可以将该查询保存在test目录中的.sql文件中。它将由dbt test命令执行。
  • 通用 测试是一个接受参数的查询。测试查询是在一个特殊的测试块(如)中定义的。定义后,您可以在整个.yml文件中按名称引用通用测试,这些文件在模型、列、源、快照和种子上定义通用测试。dbt附带了四个内置的通用测试,我们认为您应该使用它们!

定义测试是确认代码正常工作的好方法,有助于防止代码更改时出现倒退。因为您可以反复使用它们,通过微小的变化做出类似的断言,所以通用测试往往更常见——它们应该构成dbt测试套件的大部分。也就是说,定义测试的两种方法都有其合适的时候。

创建你的第一个测试

如果您是dbt新手,我们建议您查看我们的quickstart指南,以构建您的第一个带有模型和测试的dbt项目。

单例测试

定义测试的最简单方法是编写将返回失败记录的SQL。我们称这些测试为“单例”测试,因为它们是一次性的断言,可用于单一目的。

这些测试在.sql文件中定义,通常在“tests”目录中(由test-paths配置定义)。您可以在测试定义中使用Jinja(包括refsource),就像创建模型时一样。每个.sql文件包含一个select语句,它定义了一个测试:

-- Refunds have a negative amount, so the total amount should always be >= 0.
-- Therefore return records where this isn't true to make the test fail
select
    order_id,
    sum(amount) as total_amount
from {{ ref('fct_payments' )}}
group by 1
having not(total_amount >= 0)

此测试的名称是文件的名称:assert_total_payment_amount_is_positive。很简单。

单例测试很容易编写,因此您可能会发现自己一遍又一遍地编写相同的基本结构,只需更改列或模型的名称。到那时,这个测试就不那么单一了!在这种情况下,我们建议。。。

通用测试

确定的测试是通用的:它们可以反复使用。通用测试是在“测试”块中定义的,该块包含参数化查询并接受参数。它可能看起来像:

{% test not_null(model, column_name) %}

    select *
    from {{ model }}
    where {{ column_name }} is null

{% endtest %}

您会注意到有两个参数,modelcolumn_name,然后将它们模板化到查询中。这就是为什么测试是“通用的”:它可以在任意多的列上定义,也可以跨任意多的模型定义,dbt将相应地传递modelcolumn_name的值。一旦定义了通用测试,就可以将其添加为任何现有模型(或源、种子或快照)上的_属性_。这些属性被添加到位于同一目录中的.yml文件中。

注意

如果这是您第一次向资源添加属性,请查看声明属性上的文档。

开箱即用,dbt附带了四个已经定义的通用测试:unique(唯一), not_null(非空), accepted_values(可接受值) and relationships(关联关系)。以下是在订单模型上使用这些测试的完整示例

version: 2

models:
  - name: orders
    columns:
      - name: order_id
        tests:
          - unique
          - not_null
      - name: status
        tests:
          - accepted_values:
              values: ['placed', 'shipped', 'completed', 'returned']
      - name: customer_id
        tests:
          - relationships:
              to: ref('customers')
              field: id

简单地说,这些测试翻译为:

  • unique唯一: order_id 字段在 orders模型中必须是唯一
  • not_null非空: order_id 字段在 orders模型中必须是非空值
  • accepted_values可接受值: status 字段在 orders模型中必须是 'placed', 'shipped', 'completed', 或者 'returned'
  • relationships关联关系: 每个 customer_idorders 模型中必须存在一个 idcustomers 表里

在后台,dbt使用通用测试块中的参数化查询为每个测试构建一个select查询。这些查询返回断言为 真的行;如果测试返回零行,则断言通过。

您可以在参考章节中找到有关这些测试和其他配置的更多信息(包括严重性标记)。

了解更多关于通用测试

这四项测试足以让你开始使用测试。你很快就会发现你想使用更广泛的测试——这是一件好事!您也可以从包中安装通用测试,或者编写自己的测试,以便在dbt项目中使用(和重用)。查看自定义通用测试指南以了解更多信息。

注意

在一些开源软件包中定义了一些通用测试,例如dbt-utilsdbt-expectations-跳到packages上的文档以了解更多信息!

示例

要将通用测试添加到项目中,请执行以下操作:

  1. .yml文件添加到models目录,例如models/schema.yml,其中包含以下内容(您可能需要调整现有模型的name:值)

version: 2

models:
  - name: orders
    columns:
      - name: order_id
        tests:
          - unique
          - not_null

  1. 运行dbt test 命令:

$ dbt test

Found 3 models, 2 tests, 0 snapshots, 0 analyses, 130 macros, 0 operations, 0 seed files, 0 sources

17:31:05 | Concurrency: 1 threads (target='learn')
17:31:05 |
17:31:05 | 1 of 2 START test not_null_order_order_id..................... [RUN]
17:31:06 | 1 of 2 PASS not_null_order_order_id........................... [PASS in 0.99s]
17:31:06 | 2 of 2 START test unique_order_order_id....................... [RUN]
17:31:07 | 2 of 2 PASS unique_order_order_id............................. [PASS in 0.79s]
17:31:07 |
17:31:07 | Finished running 2 tests in 7.17s.

Completed successfully

Done. PASS=2 WARN=0 ERROR=0 SKIP=0 TOTAL=2
3. 通过以下方式之一检查SQL dbt是否正在运行:

  • dbt Cloud: 检查详情选项卡.
  • dbt CLI: 检查target/compiled文件夹

Unique test

select *
from (

    select
        order_id

    from analytics.orders
    where order_id is not null
    group by order_id
    having count(*) > 1

) validation_errors

select *
from (

    select
        {{ column_name }}

    from {{ model }}
    where {{ column_name }} is not null
    group by {{ column_name }}
    having count(*) > 1

) validation_errors

Not null test

select *
from analytics.orders
where order_id is null

select *
from {{ model }}
where {{ column_name }} is null

存储测试失败用例

通常,测试查询会在执行过程中统计失败次数。如果设置了可选的--store failures标记或store_failures配置,dbt将首先将测试查询的结果保存到数据库中的一个表中,然后查询该表以统计失败次数。

此工作流允许您在开发过程中更快地查询和检查失败记录:

Store test failures in the database for faster development-time debugging

请注意,如果您选择存储测试失败:

  • 默认情况下,测试结果表是在以dbt_test__audit为后缀或名称的schema中创建的。可以通过设置schema配置来更改此值。(有关schema命名的更多详细信息,请参阅使用自定义schema。)
  • 测试的结果将始终 替换 先前的失败。