Open6
【dbt】dbt_unittest

packages.yml
packages:
- package: yu-iskw/dbt_unittest
version: 0.4.0
dbt deps

dbt-unittestという便利なライブラリがあるので、こちらを使ってマクロをユニットテストできるようにしています。全てのマクロにテスト追加させるようなルールはなく、適宜追加するスタイルでやっています。仮にテストしないと不安になるような場合、マクロが複雑すぎる可能性があるのでシンプルな方向に落とすように促しています。

Jest で __tests__
フォルダにテスト用ファイルを入れるのを真似て、 __tests__
フォルダを使う
dbt_project
├─ macros
│ └─ __tests__
│ └─ test_macros.sql
└─ generate_name
├─ __tests__
│ ├─ test__generate_alias_name.sql
│ └─ test__generate_schema_name.sql
├─ generate_alias_name.sql
└─ generate_schema_name.sql
実行したいテストを下記にまとめる
test_macros.sql
{% macro test_macros() %}
{% do test__generate_alias_name() %}
{% do test__generate_schema_name() %}
{% endmacro %}
generate_schema_name.sql
{% macro generate_schema_name(custom_schema_name, node, test_target=none) -%}
{%- set effective_target = test_target if test_target is not none else target -%}
{%- if custom_schema_name is none -%} {{ effective_target.schema }}
{%- else -%} {{ custom_schema_name | trim }}
{%- endif -%}
{%- endmacro %}
test__generate_schema_name.sql
{% macro test__generate_schema_name() %}
{# カスタムスキーマが指定されている場合、それがそのまま使用される #}
{% set custom_schema_name = "custom_schema" %}
{% set node = none %}
{% set test_target = {"schema": "test_target_schema"} %}
{{
dbt_unittest.assert_equals(
dbt_project.generate_schema_name(custom_schema_name, node, test_target),
"custom_schema",
)
}}
{# カスタムスキーマが指定されていない場合、target.schema を使用する #}
{% set custom_schema_name = none %}
{% set node = none %}
{% set test_target = {"schema": "test_target_schema"} %}
{{
dbt_unittest.assert_equals(
dbt_project.generate_schema_name(custom_schema_name, node, test_target),
"test_target_schema",
)
}}
{% endmacro %}
全テスト実行
dbt run-operation test_macros
個別実行
dbt run-operation generate_schema_name
テスト失敗
15:47:45 Encountered an error while running operation: Compilation Error in macro test_macros (macros/__tests__/test_macros.sql)
FAILED: test_target_schema does not equal test_target_schema2.
> in macro assert_equals (macros/assert_equals.sql)
> called by macro test__generate_schema_name (macros/generate_name/__tests__/test__generate_schema_name.sql)
> called by macro test_macros (macros/__tests__/test_macros.sql)
> called by macro test_macros (macros/__tests__/test_macros.sql)

WIP
dbtでマクロのユニットテストをJest風に書く構成
概要
dbt
のマクロの挙動をユニットテストで担保したい場合、dbt-unittest のようなライブラリと run-operation
を使って検証できます。本記事では、Jest風に __tests__
フォルダを用いてテストコードを整理し、各マクロのテストをモジュールごとに管理する構成を紹介します。
ディレクトリ構成
以下のように、各マクロディレクトリに __tests__
フォルダを設けてテストを分離します:
dbt_project/
├─ macros/
│ └─ __tests__/
│ └─ test_macros.sql # 全体のエントリーポイント
├─ generate_name/
│ ├─ __tests__/
│ │ ├─ test__generate_alias_name.sql
│ │ └─ test__generate_schema_name.sql
│ ├─ generate_alias_name.sql
│ └─ generate_schema_name.sql
Jest では __tests__
フォルダを用いてテストコードを分離管理する文化がありますが、dbt でも似たような思想で管理するとスッキリします。
テストコードの書き方
例として generate_schema_name
マクロのテストを書いてみます。
generate_name/generate_schema_name.sql
)
マクロ本体({% macro generate_schema_name(custom_schema_name, node, test_target=none) -%}
{%- set effective_target = test_target if test_target is not none else target -%}
{%- if custom_schema_name is none -%} {{ effective_target.schema }}
{%- else -%} {{ custom_schema_name | trim }}
{%- endif -%}
{%- endmacro %}
generate_name/__tests__/test__generate_schema_name.sql
)
テストコード({% macro test__generate_schema_name() %}
{# カスタムスキーマが指定されている場合、それがそのまま使用される #}
{% set custom_schema_name = "custom_schema" %}
{% set node = none %}
{% set test_target = {"schema": "test_target_schema"} %}
{{
dbt_unittest.assert_equals(
dbt_project.generate_schema_name(custom_schema_name, node, test_target),
"custom_schema",
)
}}
{# カスタムスキーマが指定されていない場合、target.schema を使用する #}
{% set custom_schema_name = none %}
{% set node = none %}
{% set test_target = {"schema": "test_target_schema"} %}
{{
dbt_unittest.assert_equals(
dbt_project.generate_schema_name(custom_schema_name, node, test_target),
"test_target_schema",
)
}}
{% endmacro %}
テストマクロのエントリーポイント
すべてのテストをまとめて実行するためのエントリーポイントを作成します(macros/__tests__/test_macros.sql
):
{% macro test_macros() %}
{% do test__generate_alias_name() %}
{% do test__generate_schema_name() %}
{% endmacro %}
実行方法
全テストを実行
dbt run-operation test_macros
個別のマクロを手動で試す
dbt run-operation generate_schema_name
テスト失敗時の出力例
失敗時は下記のように明確にエラー箇所がログに表示されます:
Encountered an error while running operation: Compilation Error in macro test_macros (macros/__tests__/test_macros.sql)
FAILED: test_target_schema does not equal test_target_schema2.
> in macro assert_equals (macros/assert_equals.sql)
> called by macro test__generate_schema_name (macros/generate_name/__tests__/test__generate_schema_name.sql)
> called by macro test_macros (macros/__tests__/test_macros.sql)
まとめ
- Jestライクに
__tests__
フォルダでマクロごとのテストを管理すると見通しが良くなる。 -
dbt run-operation
を使うことでユニットテストが簡単に実行できる。 -
dbt_unittest
を使えば、assert_equals
やassert_in
などの便利な検証ができる。
マクロを共通化していくプロジェクトでは、このようなテスト戦略を早めに取り入れておくと、将来的な変更に強くなります。