From 27a25e693ea3b03ca82ad5db1bdaaae298c6322c Mon Sep 17 00:00:00 2001 From: Bruno Souza de Lima Date: Wed, 5 Mar 2025 14:39:50 -0300 Subject: [PATCH 1/9] adding generate_unit_test_template_macro --- macros/generate_unit_test_template.sql | 100 +++++++++++++++++++++++++ macros/helpers/helpers.sql | 17 ++++- 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 macros/generate_unit_test_template.sql diff --git a/macros/generate_unit_test_template.sql b/macros/generate_unit_test_template.sql new file mode 100644 index 0000000..5424767 --- /dev/null +++ b/macros/generate_unit_test_template.sql @@ -0,0 +1,100 @@ +{% macro generate_unit_test_template(model_name, expected_rows=true) %} + + {%- set ns = namespace(depends_on_list = []) -%} + + -- getting inputs and materialization info + {%- for node in graph.nodes.values() + | selectattr("resource_type", "equalto", "model") + | selectattr("name", "equalto", model_name) -%} + {%- set ns.depends_on_list = ns.depends_on_list + node.depends_on.nodes -%} + {%- set ns.this_materialization = node.config['materialized'] -%} + {%- endfor -%} + + -- getting the input columns + {%- set ns.input_columns_list = [] -%} + {%- for item in ns.depends_on_list -%} + {%- set input_columns_list = [] -%} + {%- set item_dict = get_resource_from_unique_id(item) -%} + {%- if item_dict.resource_type == 'source' %} + {%- set columns = adapter.get_columns_in_relation(source(item_dict.source_name, item_dict.identifier)) -%} + {%- else -%} + {%- set columns = adapter.get_columns_in_relation(ref(item_dict.alias)) -%} + {%- endif -%} + {%- for column in columns -%} + {{ input_columns_list.append(column.name) }} + {%- endfor -%} + {{ ns.input_columns_list.append(input_columns_list) }} + {%- endfor -%} + + -- getting 'this' columns + {%- set ns.expected_columns_list = [] -%} + {%- set columns = adapter.get_columns_in_relation(ref(model_name)) -%} + {%- for column in columns -%} + {{ ns.expected_columns_list.append(column.name) }} + {%- endfor -%} + + {%- set unit_test_yaml_template -%} +unit_tests: + - name: unit_test_{{ model_name }} + model: {{ model_name }} + {% if ns.this_materialization == 'incremental' %} + overrides: + macros: + is_incremental: true + {% endif %} + given: + {%- for i in range(ns.depends_on_list|length) -%} + {%- set item_dict = get_resource_from_unique_id(ns.depends_on_list[i]) -%} + {% if item_dict.resource_type == 'source' %} + - input: source("{{item_dict.source_name}}", "{{item_dict.identifier}}") + rows: + {%- else %} + - input: ref("{{item_dict.alias}}") + rows: + {%- endif -%} + {%- set ns.column_string = '- {' -%} + {%- for column_name in ns.input_columns_list[i] -%} + {%- if not loop.last -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} + {%- endif -%} + {% endfor %} + {{ns.column_string}} + {% endfor %} + + {%- if ns.this_materialization == 'incremental' -%} + - input: this + rows: + {%- if expected_rows -%} + {%- set ns.column_string = '- {' -%} + {%- for column_name in ns.expected_columns_list -%} + {%- if not loop.last -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} + {%- endif -%} + {% endfor %} + {{ns.column_string}} + {% endif %} + {% endif %} + + expect: + rows: + {%- if expected_rows -%} + {%- set ns.column_string = '- {' -%} + {%- for column_name in ns.expected_columns_list -%} + {%- if not loop.last -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} + {%- endif -%} + {% endfor %} + {{ns.column_string}} + {%- endif -%} + + {%- endset -%} + + {{ print(unit_test_yaml_template) }} + +{% endmacro %} \ No newline at end of file diff --git a/macros/helpers/helpers.sql b/macros/helpers/helpers.sql index 086e57e..cf4eeb4 100644 --- a/macros/helpers/helpers.sql +++ b/macros/helpers/helpers.sql @@ -48,7 +48,7 @@ {% set model_path = "/".join(model.path.split("/")[:-1]) %} {% if model_path == directory and model.name.startswith(prefix) %} {% do model_names.append(model.name) %} - {% endif %} + {% endif %} {% endfor %} {% elif directory %} {% for model in models %} @@ -88,3 +88,18 @@ {% set formatted = codegen.format_column(column) %} {{ return(formatted['data_type'] | lower) }} {% endmacro %} + +{# retrieve entire resource dictionary based on unique id #} +{% macro get_resource_from_unique_id(resource_unique_id) %} + {% set resource_type = resource_unique_id.split('.')[0] %} + {% if resource_type == 'source' %} + {% set resource = graph.sources[resource_unique_id] %} + {% elif resource_type == 'exposure' %} + {% set resource = graph.exposure[resource_unique_id] %} + {% elif resource_type == 'metric' %} + {% set resource = graph.metrics[resource_unique_id] %} + {% else %} + {% set resource = graph.nodes[resource_unique_id] %} + {% endif %} + {{ return(resource) }} +{% endmacro %} \ No newline at end of file From 8d04c51fb9625856a188040f244d10a2cef827a7 Mon Sep 17 00:00:00 2001 From: Bruno Souza de Lima Date: Wed, 5 Mar 2025 14:57:09 -0300 Subject: [PATCH 2/9] added a relation exists check --- macros/generate_unit_test_template.sql | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/macros/generate_unit_test_template.sql b/macros/generate_unit_test_template.sql index 5424767..9e1133e 100644 --- a/macros/generate_unit_test_template.sql +++ b/macros/generate_unit_test_template.sql @@ -1,4 +1,4 @@ -{% macro generate_unit_test_template(model_name, expected_rows=true) %} +{% macro generate_unit_test_template(model_name) %} {%- set ns = namespace(depends_on_list = []) -%} @@ -27,11 +27,14 @@ {%- endfor -%} -- getting 'this' columns - {%- set ns.expected_columns_list = [] -%} - {%- set columns = adapter.get_columns_in_relation(ref(model_name)) -%} - {%- for column in columns -%} - {{ ns.expected_columns_list.append(column.name) }} - {%- endfor -%} + {% set relation_exists = load_relation(ref(model_name)) is not none %} + {% if relation_exists %} + {%- set ns.expected_columns_list = [] -%} + {%- set columns = adapter.get_columns_in_relation(ref(model_name)) -%} + {%- for column in columns -%} + {{ ns.expected_columns_list.append(column.name) }} + {%- endfor -%} + {% endif %} {%- set unit_test_yaml_template -%} unit_tests: @@ -66,7 +69,7 @@ unit_tests: {%- if ns.this_materialization == 'incremental' -%} - input: this rows: - {%- if expected_rows -%} + {%- if relation_exists -%} {%- set ns.column_string = '- {' -%} {%- for column_name in ns.expected_columns_list -%} {%- if not loop.last -%} @@ -81,7 +84,7 @@ unit_tests: expect: rows: - {%- if expected_rows -%} + {%- if relation_exists -%} {%- set ns.column_string = '- {' -%} {%- for column_name in ns.expected_columns_list -%} {%- if not loop.last -%} From 83996c14ee1472c503e728bbd3538992896770b0 Mon Sep 17 00:00:00 2001 From: Bruno Souza de Lima Date: Wed, 12 Mar 2025 16:57:55 -0300 Subject: [PATCH 3/9] adding arg to controle inline/multiline columns --- macros/generate_unit_test_template.sql | 100 ++++++++++++++++++------- 1 file changed, 74 insertions(+), 26 deletions(-) diff --git a/macros/generate_unit_test_template.sql b/macros/generate_unit_test_template.sql index 9e1133e..d215d7e 100644 --- a/macros/generate_unit_test_template.sql +++ b/macros/generate_unit_test_template.sql @@ -1,4 +1,4 @@ -{% macro generate_unit_test_template(model_name) %} +{% macro generate_unit_test_template(model_name, inline_columns=false) %} {%- set ns = namespace(depends_on_list = []) -%} @@ -55,44 +55,77 @@ unit_tests: - input: ref("{{item_dict.alias}}") rows: {%- endif -%} - {%- set ns.column_string = '- {' -%} - {%- for column_name in ns.input_columns_list[i] -%} - {%- if not loop.last -%} - {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} - {%- else -%} - {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} - {%- endif -%} - {% endfor %} + {%- if inline_columns -%} + {%- set ns.column_string = '- {' -%} + {%- for column_name in ns.input_columns_list[i] -%} + {%- if not loop.last -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} + {%- endif -%} + {% endfor %} + {%- else -%} + {%- set ns.column_string = '' -%} + {%- for column_name in ns.input_columns_list[i] -%} + {%- if loop.first -%} + {%- set ns.column_string = ns.column_string ~ '- ' ~ column_name ~ ': ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ '\n ' ~ column_name ~ ': ' -%} + {%- endif -%} + {% endfor %} + {%- endif %} {{ns.column_string}} {% endfor %} - {%- if ns.this_materialization == 'incremental' -%} + {%- if ns.this_materialization == 'incremental' %} - input: this rows: {%- if relation_exists -%} - {%- set ns.column_string = '- {' -%} - {%- for column_name in ns.expected_columns_list -%} - {%- if not loop.last -%} - {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} - {%- else -%} - {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} - {%- endif -%} - {% endfor %} + {%- if inline_columns -%} + {%- set ns.column_string = '- {' -%} + {%- for column_name in ns.expected_columns_list -%} + {%- if not loop.last -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} + {%- endif -%} + {% endfor %} + {%- else -%} + {%- set ns.column_string = '' -%} + {%- for column_name in ns.expected_columns_list -%} + {%- if loop.first -%} + {%- set ns.column_string = ns.column_string ~ '- ' ~ column_name ~ ': ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ '\n ' ~ column_name ~ ': ' -%} + {%- endif -%} + {% endfor %} + {%- endif %} {{ns.column_string}} - {% endif %} + {%- endif %} {% endif %} expect: rows: {%- if relation_exists -%} - {%- set ns.column_string = '- {' -%} - {%- for column_name in ns.expected_columns_list -%} - {%- if not loop.last -%} - {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} + {%- if inline_columns -%} + {%- set ns.column_string = '- {' -%} + {%- for column_name in ns.expected_columns_list -%} + {%- if not loop.last -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': , ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} + {%- endif -%} + {% endfor %} {%- else -%} - {%- set ns.column_string = ns.column_string ~ column_name ~ ': }' -%} - {%- endif -%} - {% endfor %} + {%- set ns.column_string = '' -%} + {%- for column_name in ns.expected_columns_list -%} + {%- if loop.first -%} + {%- set ns.column_string = ns.column_string ~ '- ' ~ column_name ~ ': ' -%} + {%- else -%} + {%- set ns.column_string = ns.column_string ~ '\n ' ~ column_name ~ ': ' -%} + {%- endif -%} + {% endfor %} + {%- endif %} {{ns.column_string}} {%- endif -%} @@ -100,4 +133,19 @@ unit_tests: {{ print(unit_test_yaml_template) }} +{% endmacro %} + +{# retrieve entire resource dictionary based on unique id #} +{% macro get_resource_from_unique_id(resource_unique_id) %} + {% set resource_type = resource_unique_id.split('.')[0] %} + {% if resource_type == 'source' %} + {% set resource = graph.sources[resource_unique_id] %} + {% elif resource_type == 'exposure' %} + {% set resource = graph.exposure[resource_unique_id] %} + {% elif resource_type == 'metric' %} + {% set resource = graph.metrics[resource_unique_id] %} + {% else %} + {% set resource = graph.nodes[resource_unique_id] %} + {% endif %} + {{ return(resource) }} {% endmacro %} \ No newline at end of file From 809991d054187cabad108f188259b5b39c4ba418 Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Mon, 24 Mar 2025 11:41:41 -0600 Subject: [PATCH 4/9] Removing duplicated `get_resource_from_unique_id` macro --- macros/generate_unit_test_template.sql | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/macros/generate_unit_test_template.sql b/macros/generate_unit_test_template.sql index d215d7e..8692125 100644 --- a/macros/generate_unit_test_template.sql +++ b/macros/generate_unit_test_template.sql @@ -134,18 +134,3 @@ unit_tests: {{ print(unit_test_yaml_template) }} {% endmacro %} - -{# retrieve entire resource dictionary based on unique id #} -{% macro get_resource_from_unique_id(resource_unique_id) %} - {% set resource_type = resource_unique_id.split('.')[0] %} - {% if resource_type == 'source' %} - {% set resource = graph.sources[resource_unique_id] %} - {% elif resource_type == 'exposure' %} - {% set resource = graph.exposure[resource_unique_id] %} - {% elif resource_type == 'metric' %} - {% set resource = graph.metrics[resource_unique_id] %} - {% else %} - {% set resource = graph.nodes[resource_unique_id] %} - {% endif %} - {{ return(resource) }} -{% endmacro %} \ No newline at end of file From ee54da86edd888161a9a69864809d6ed5962aabb Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Wed, 2 Apr 2025 17:30:23 -0600 Subject: [PATCH 5/9] Add newline to end of file --- macros/helpers/helpers.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macros/helpers/helpers.sql b/macros/helpers/helpers.sql index cf4eeb4..d7fa19e 100644 --- a/macros/helpers/helpers.sql +++ b/macros/helpers/helpers.sql @@ -102,4 +102,4 @@ {% set resource = graph.nodes[resource_unique_id] %} {% endif %} {{ return(resource) }} -{% endmacro %} \ No newline at end of file +{% endmacro %} From 5e8ec303c33ba7621cd9f7ab53cb183f566a0eda Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Wed, 2 Apr 2025 17:31:36 -0600 Subject: [PATCH 6/9] Add a simple incremental model for testing --- integration_tests/models/model_incremental.sql | 5 +++++ integration_tests/tests/test_helper_get_models.sql | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 integration_tests/models/model_incremental.sql diff --git a/integration_tests/models/model_incremental.sql b/integration_tests/models/model_incremental.sql new file mode 100644 index 0000000..407e284 --- /dev/null +++ b/integration_tests/models/model_incremental.sql @@ -0,0 +1,5 @@ +{{ config( + materialized='incremental' +) }} + +select 1 as id diff --git a/integration_tests/tests/test_helper_get_models.sql b/integration_tests/tests/test_helper_get_models.sql index 95c4d0c..1c0a32a 100644 --- a/integration_tests/tests/test_helper_get_models.sql +++ b/integration_tests/tests/test_helper_get_models.sql @@ -1,4 +1,5 @@ -- depends_on: {{ ref('model_data_a') }} +-- depends_on: {{ ref('model_incremental') }} -- depends_on: {{ ref('model_struct') }} -- depends_on: {{ ref('model_without_import_ctes') }} -- depends_on: {{ ref('model_without_any_ctes') }} @@ -7,6 +8,6 @@ {% set actual_list = codegen.get_models(prefix='model_')|sort %} {% endif %} -{% set expected_list = ['model_data_a', 'model_from_source', 'model_repeated', 'model_struct', 'model_without_any_ctes', 'model_without_import_ctes'] %} +{% set expected_list = ['model_data_a', 'model_from_source', 'model_incremental', 'model_repeated', 'model_struct', 'model_without_any_ctes', 'model_without_import_ctes'] %} {{ assert_equal (actual_list, expected_list) }} From bbad2e2b7d70a52540cb37a4c4abcfddab166a31 Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Wed, 2 Apr 2025 18:06:21 -0600 Subject: [PATCH 7/9] CI tests --- .../test_generate_unit_test_template.sql | 28 +++++++++++++++++++ ...enerate_unit_test_template_incremental.sql | 28 +++++++++++++++++++ ...rate_unit_test_template_inline_columns.sql | 26 +++++++++++++++++ ...e_unit_test_template_model_from_source.sql | 26 +++++++++++++++++ ..._generate_unit_test_template_no_inputs.sql | 23 +++++++++++++++ 5 files changed, 131 insertions(+) create mode 100644 integration_tests/tests/test_generate_unit_test_template.sql create mode 100644 integration_tests/tests/test_generate_unit_test_template_incremental.sql create mode 100644 integration_tests/tests/test_generate_unit_test_template_inline_columns.sql create mode 100644 integration_tests/tests/test_generate_unit_test_template_model_from_source.sql create mode 100644 integration_tests/tests/test_generate_unit_test_template_no_inputs.sql diff --git a/integration_tests/tests/test_generate_unit_test_template.sql b/integration_tests/tests/test_generate_unit_test_template.sql new file mode 100644 index 0000000..8a482b7 --- /dev/null +++ b/integration_tests/tests/test_generate_unit_test_template.sql @@ -0,0 +1,28 @@ +{% set actual_model_yaml = codegen.generate_unit_test_template( + model_name='child_model', + inline_columns=False + ) +%} + +-- depends_on: {{ ref('model_data_a') }} +-- depends_on: {{ ref('child_model') }} + +{% set expected_model_yaml %} +unit_tests: + - name: unit_test_child_model + model: child_model + + given: + - input: ref("model_data_a") + rows: + - col_a: + col_b: + + expect: + rows: + - col_a: + col_b: + +{% endset %} + +{{ assert_equal (actual_model_yaml | trim, expected_model_yaml | trim) }} diff --git a/integration_tests/tests/test_generate_unit_test_template_incremental.sql b/integration_tests/tests/test_generate_unit_test_template_incremental.sql new file mode 100644 index 0000000..433cbfb --- /dev/null +++ b/integration_tests/tests/test_generate_unit_test_template_incremental.sql @@ -0,0 +1,28 @@ +{% set actual_model_yaml = codegen.generate_unit_test_template( + model_name='model_incremental', + ) +%} + +-- depends_on: {{ ref('model_incremental') }} + +{% set expected_model_yaml %} +unit_tests: + - name: unit_test_model_incremental + model: model_incremental + + overrides: + macros: + is_incremental: true + + given: + - input: this + rows: + - id: + + expect: + rows: + - id: + +{% endset %} + +{{ assert_equal (actual_model_yaml | trim, expected_model_yaml | trim) }} diff --git a/integration_tests/tests/test_generate_unit_test_template_inline_columns.sql b/integration_tests/tests/test_generate_unit_test_template_inline_columns.sql new file mode 100644 index 0000000..b45cc74 --- /dev/null +++ b/integration_tests/tests/test_generate_unit_test_template_inline_columns.sql @@ -0,0 +1,26 @@ +{% set actual_model_yaml = codegen.generate_unit_test_template( + model_name='child_model', + inline_columns=True + ) +%} + +-- depends_on: {{ ref('model_data_a') }} +-- depends_on: {{ ref('child_model') }} + +{% set expected_model_yaml %} +unit_tests: + - name: unit_test_child_model + model: child_model + + given: + - input: ref("model_data_a") + rows: + - {col_a: , col_b: } + + expect: + rows: + - {col_a: , col_b: } + +{% endset %} + +{{ assert_equal (actual_model_yaml | trim, expected_model_yaml | trim) }} diff --git a/integration_tests/tests/test_generate_unit_test_template_model_from_source.sql b/integration_tests/tests/test_generate_unit_test_template_model_from_source.sql new file mode 100644 index 0000000..f89f196 --- /dev/null +++ b/integration_tests/tests/test_generate_unit_test_template_model_from_source.sql @@ -0,0 +1,26 @@ +{% set actual_model_yaml = codegen.generate_unit_test_template( + model_name='model_from_source', + ) +%} + +-- depends_on: {{ ref('model_from_source') }} + +{% set expected_model_yaml %} +unit_tests: + - name: unit_test_model_from_source + model: model_from_source + + given: + - input: source("codegen_integration_tests__data_source_schema", "codegen_integration_tests__data_source_table") + rows: + - my_integer_col: + my_bool_col: + + expect: + rows: + - my_integer_col: + my_bool_col: + +{% endset %} + +{{ assert_equal (actual_model_yaml | trim, expected_model_yaml | trim) }} diff --git a/integration_tests/tests/test_generate_unit_test_template_no_inputs.sql b/integration_tests/tests/test_generate_unit_test_template_no_inputs.sql new file mode 100644 index 0000000..e915655 --- /dev/null +++ b/integration_tests/tests/test_generate_unit_test_template_no_inputs.sql @@ -0,0 +1,23 @@ +{% set actual_model_yaml = codegen.generate_unit_test_template( + model_name='data__a_relation', + inline_columns=False + ) +%} + +-- depends_on: {{ ref('data__a_relation') }} + +{% set expected_model_yaml %} +unit_tests: + - name: unit_test_data__a_relation + model: data__a_relation + + given: [] + + expect: + rows: + - col_a: + col_b: + +{% endset %} + +{{ assert_equal (actual_model_yaml | trim, expected_model_yaml | trim) }} From 3a660ea9aa793101cfcedd478dec411e6931d58d Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Wed, 2 Apr 2025 18:09:22 -0600 Subject: [PATCH 8/9] Use dispatch, etc. --- macros/generate_unit_test_template.sql | 31 +++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/macros/generate_unit_test_template.sql b/macros/generate_unit_test_template.sql index 8692125..36afba2 100644 --- a/macros/generate_unit_test_template.sql +++ b/macros/generate_unit_test_template.sql @@ -1,7 +1,13 @@ {% macro generate_unit_test_template(model_name, inline_columns=false) %} + {{ return(adapter.dispatch('generate_unit_test_template', 'codegen')(model_name, inline_columns)) }} +{% endmacro %} + +{% macro default__generate_unit_test_template(model_name, inline_columns=false) %} {%- set ns = namespace(depends_on_list = []) -%} + {%- if execute -%} + -- getting inputs and materialization info {%- for node in graph.nodes.values() | selectattr("resource_type", "equalto", "model") @@ -10,11 +16,13 @@ {%- set ns.this_materialization = node.config['materialized'] -%} {%- endfor -%} + {%- endif -%} + -- getting the input columns {%- set ns.input_columns_list = [] -%} {%- for item in ns.depends_on_list -%} {%- set input_columns_list = [] -%} - {%- set item_dict = get_resource_from_unique_id(item) -%} + {%- set item_dict = codegen.get_resource_from_unique_id(item) -%} {%- if item_dict.resource_type == 'source' %} {%- set columns = adapter.get_columns_in_relation(source(item_dict.source_name, item_dict.identifier)) -%} {%- else -%} @@ -40,14 +48,16 @@ unit_tests: - name: unit_test_{{ model_name }} model: {{ model_name }} - {% if ns.this_materialization == 'incremental' %} +{% if ns.this_materialization == 'incremental' %} overrides: macros: is_incremental: true - {% endif %} - given: +{% else -%} + +{%- endif %} + given: {%- if ns.depends_on_list|length == 0 and ns.this_materialization != 'incremental' %} []{% endif %} {%- for i in range(ns.depends_on_list|length) -%} - {%- set item_dict = get_resource_from_unique_id(ns.depends_on_list[i]) -%} + {%- set item_dict = codegen.get_resource_from_unique_id(ns.depends_on_list[i]) -%} {% if item_dict.resource_type == 'source' %} - input: source("{{item_dict.source_name}}", "{{item_dict.identifier}}") rows: @@ -75,7 +85,7 @@ unit_tests: {% endfor %} {%- endif %} {{ns.column_string}} - {% endfor %} + {%- endfor %} {%- if ns.this_materialization == 'incremental' %} - input: this @@ -102,7 +112,7 @@ unit_tests: {%- endif %} {{ns.column_string}} {%- endif %} - {% endif %} + {%- endif %} expect: rows: @@ -131,6 +141,11 @@ unit_tests: {%- endset -%} - {{ print(unit_test_yaml_template) }} + {% if execute %} + + {{ print(unit_test_yaml_template) }} + {% do return(unit_test_yaml_template) %} + + {% endif %} {% endmacro %} From 1425cd20ef25ca6a59b8a2de1de52c09193b8a0c Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Wed, 2 Apr 2025 18:26:20 -0600 Subject: [PATCH 9/9] Usage documentation for `generate_unit_test_template` macro --- README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/README.md b/README.md index ae1d8e0..438d248 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,9 @@ Macros that generate dbt code, and log it to the command line. - [generate_model_import_ctes (source)](#generate_model_import_ctes-source) - [Arguments:](#arguments-5) - [Usage:](#usage-5) + - [generate_unit_test_template (source)](#generate_unit_test_template-source) + - [Arguments:](#arguments-6) + - [Usage:](#usage-6) - [Contributing](#contributing) # Installation instructions @@ -394,6 +397,45 @@ select * from final 4. Replace the contents of the model's current SQL file with the compiled or logged code +## generate_unit_test_template ([source](macros/generate_unit_test_template.sql)) + +This macro generates the unit testing YAML for a given model with all references included as `given` inputs (along with their columns), plus the columns within the expected output. + +### Arguments: + +- `model_name` (required): The model you wish to generate unit testing YAML for. +- `inline_columns` (optional, default=False): Whether you want all columns on the same line. + +### Usage: + +1. Create a model with your original SQL query +2. Call the macro as an [operation](https://docs.getdbt.com/docs/using-operations): + +``` +$ dbt run-operation generate_unit_test_template --args '{"model_name": "order_items", "inline_columns": true}' +``` + +3. The new YAML - with all given inputs included - will be logged to the command line + +```yaml +unit_tests: + - name: unit_test_order_items + model: order_items + + given: + - input: ref("stg_order_items") + rows: + - col_a: + col_b: + + expect: + rows: + - id: +``` + +4. Create a new YAML file with the compiled or logged code. +5. Add column values for the given inputs and expected output. + ## Contributing To contirbute code to this package, please follow the steps outlined in the `integration_tests` directory's [README](https://github.com/dbt-labs/dbt-codegen/blob/main/integration_tests/README.md) file.