Skip to content

Commit bb5fbd1

Browse files
committed
Add expect_no_rows macro
1 parent 94ff85e commit bb5fbd1

File tree

5 files changed

+91
-8
lines changed

5 files changed

+91
-8
lines changed

README.md

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,23 @@ UNION ALL
154154
{% endcall %}
155155
```
156156

157+
### Expectations
158+
159+
The expectations are the results you expect from the model. The framework compares the expectations with the actuals and shows the differences in the test report.
160+
161+
```jinja
162+
{% call dbt_unit_testing.expect() %}
163+
select ...
164+
{% endcall %}
165+
```
166+
167+
You can use the macro `expect_no_rows` to test if the model returns no rows:
168+
169+
```jinja
170+
{% call dbt_unit_testing.expect_no_rows() %}
171+
{% endcall %}
172+
```
173+
157174
## Running tests
158175

159176
The framework leverages the dbt test command to run the tests. You can run all the tests in your project with the following command:
@@ -170,12 +187,13 @@ dbt test --select tag:unit-test
170187

171188
## Available Macros
172189

173-
| macro name | description |
174-
|------------------------------|-------------------------------------------------|
175-
| dbt_unit_testing.test | Defines a Test |
176-
| dbt_unit_testing.mock_ref | Mocks a **model** / **snapshot** / **seed** |
177-
| dbt_unit_testing.mock_source | Mocks a **source** |
178-
| dbt_unit_testing.expect | Defines Test expectations |
190+
| macro name | description |
191+
|---------------------------------|-------------------------------------------------|
192+
| dbt_unit_testing.test | Defines a Test |
193+
| dbt_unit_testing.mock_ref | Mocks a **model** / **snapshot** / **seed** |
194+
| dbt_unit_testing.mock_source | Mocks a **source** |
195+
| dbt_unit_testing.expect | Defines the Test expectations |
196+
| dbt_unit_testing.expect_no_rows | Used to test if the model returns no rows |
179197

180198
## Test Examples
181199

@@ -701,6 +719,7 @@ In this example, the `activity_details` column, which is a struct, is transforme
701719
| **count_column** | The name of the `count` column in the test report | count| project/test |
702720
| **run_as_incremental** | Runs the model in `incremental` mode (it has no effect if the model is not incremental) | false| project/test |
703721
| **column_transformations** | A JSON structure specifying the desired transformations for each column. See [Column Transformations](#column-transformations) for more details. | {}| project/test |
722+
| last_spaces_replace_char | Replace the spaces at the end of the values with another character. See [Test Feedback](#test-feedback) for more details. | (space) | project/test |
704723

705724
Notes:
706725

@@ -740,6 +759,28 @@ Rows mismatch:
740759

741760
The first line was not on the model, but the second line was.
742761

762+
### Spaces at the end of the diff values
763+
764+
It can be hard to spot the difference when the values have spaces at the end. To avoid this, you can use the option `last_spaces_replace_char` to replace the spaces at the end of the values with another character:
765+
766+
```yaml
767+
vars:
768+
unit_tests_config:
769+
last_spaces_replace_char: "."
770+
```
771+
772+
This will replace the spaces at the end of the values with a dot. The result will be displayed like this:
773+
774+
```yaml
775+
MODEL: customers
776+
TEST: should sum order values to calculate customer_lifetime_value
777+
Rows mismatch:
778+
| diff | count | some_column |
779+
| ---- | ----- | ----------- |
780+
| + | 1 | John |
781+
| - | 1 | John.. |
782+
```
783+
743784
# Known Limitations
744785

745786
- You can not have a *model* with the same name as a *source* or a *seed* (unless you set the *use_qualified_sources* option to *true*).
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{{
2+
config(
3+
tags=['unit-test', 'bigquery', 'snowflake', 'postgres']
4+
)
5+
}}
6+
7+
{% call dbt_unit_testing.test('model_b_references_a', 'sample test') %}
8+
{% call dbt_unit_testing.mock_ref ('model_a') %}
9+
select 0 as a, 'a' as b
10+
{% endcall %}
11+
{% call dbt_unit_testing.expect_no_rows() %}
12+
{% endcall %}
13+
{% endcall %}

macros/mock_builders.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@
5353
{{ return (dbt_unit_testing.append_json(expectations)) }}
5454
{% endmacro %}
5555

56+
{% macro expect_no_rows(options={}) %}
57+
{% set dummy = caller() %}
58+
{% set expectations = {
59+
"type": "expectations",
60+
"options": options,
61+
"input_values": "select a from (select 1 as a) as s where false",
62+
}
63+
%}
64+
{{ return (dbt_unit_testing.append_json(expectations)) }}
65+
{% endmacro %}
66+
5667
{% macro append_json(json) %}
5768
{{ return (json | tojson() ~ '####_JSON_LINE_DELIMITER_####') }}
5869
{% endmacro %}

macros/output.sql

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% macro print_table(agate_table) %}
1+
{% macro print_table(agate_table, options={}) %}
22
{% set columns_start_index = 2 %}
33
{% set columns_info = [] %}
44
{% for col_name in agate_table.column_names %}
@@ -47,10 +47,14 @@
4747
{% endfor %}
4848
{{ dbt_unit_testing.println("| " ~ cells | join(" | ") ~ " |")}}
4949

50+
{% set last_spaces_replace_char = options.last_spaces_replace_char | default(" ") %}
5051
{% for row in agate_table.rows %}
5152
{% set cells = [] %}
5253
{% for cell_value in row %}
5354
{% set col_index = loop.index0 %}
55+
{% if cell_value is string %}
56+
{% set cell_value = dbt_unit_testing.replace_last_spaces_with(last_spaces_replace_char, cell_value) %}
57+
{% endif %}
5458
{% set padded = dbt_unit_testing.pad(cell_value, columns_info[col_index].max_length, pad_right=cell_value is string) %}
5559
{% if columns_info[col_index].has_differences %}
5660
{% do cells.append("{RED}" ~ padded ~ "{RESET}") %}
@@ -60,7 +64,20 @@
6064
{% endfor %}
6165
{{ dbt_unit_testing.println("| " ~ cells | join(" | ") ~ " |")}}
6266
{% endfor %}
67+
{% endmacro %}
6368

69+
{% macro replace_last_spaces_with(replacement, s) %}
70+
{% set rs = s | reverse %}
71+
{% set replaced = namespace(value="", stop=false) %}
72+
{% for i in range(0, rs | length) %}
73+
{% if rs[i] == ' ' and not replaced.stop %}
74+
{% set replaced.value = replaced.value ~ replacement %}
75+
{% else %}
76+
{% set replaced.value = replaced.value ~ rs[i] %}
77+
{% set replaced.stop = true %}
78+
{% endif %}
79+
{% endfor %}
80+
{{ return(replaced.value | reverse) }}
6481
{% endmacro %}
6582

6683
{% macro pad(v, pad, pad_right=false, c=" ") %}
@@ -77,6 +94,7 @@
7794
.replace("{RED}", "\x1b[0m\x1b[31m")
7895
.replace("{GREEN}", "\x1b[0m\x1b[32m")
7996
.replace("{YELLOW}", "\x1b[0m\x1b[33m")
97+
.replace("{BG_YELLOW}", "\x1b[0m\x1b[43m")
8098
.replace("{RESET}", "\x1b[0m")) }}
8199
{% endmacro %}
82100

macros/tests.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@
147147
{% endif %}
148148
{% if test_report.different_rows_count > 0 %}
149149
{{ dbt_unit_testing.println('{RED}ERROR: {YELLOW}Rows mismatch:') }}
150-
{{ dbt_unit_testing.print_table(test_report.test_differences) }}
150+
{{ dbt_unit_testing.print_table(test_report.test_differences, options=test_configuration.options) }}
151151
{% endif %}
152152
{% endmacro %}
153153

0 commit comments

Comments
 (0)