# Unit testing a macro with separate models

**URL:** <https://discourse.getdbt.com/t/unit-testing-a-macro-with-separate-models/19975>\
**Category:** Help\
**Tags:** testing, macros, dbt-core\
**Created:** [July 29, 2025, 9:19am UTC](https://discourse.getdbt.com/t/unit-testing-a-macro-with-separate-models/19975 "2025-07-29T09:19:25Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![cmartin28](https://sea2.discourse-cdn.com/flex020/user_avatar/discourse.getdbt.com/cmartin28/32/5533_2.png) [@cmartin28](https://discourse.getdbt.com/u/cmartin28)\
**Post date:** [July 29, 2025, 9:19am UTC](https://discourse.getdbt.com/t/unit-testing-a-macro-with-separate-models/19975/1 "2025-07-29T09:19:25Z")

</div>

Hello,

I have a macro called `age_binning` that is essentially a CASE statement that looks like this

```auto
# age_binning.sql

{%- macro age_binning(age_column) -%}
    case
        when {{ age_column }} between 10 and 19 then 'val_1'
        when {{ age_column }} between 20 and 29 then 'val_2'
        ...
    end
{%- endmacro -%}

```

that I would like to be able to test the logic of this macro. My approach was to create a tiny model that is dedicated to testing this macro called `macro_test_age_binning`

```auto
# macro_test_age_binning.sql

with
    dummy_data as (
        select
        null::int as age
    )
select
    dummy_data.age,
    {{ age_binning('dummy_data.age') }} as age_group
from dummy_data 

```

I created a unit\_test in order to validate the macro:

```auto
-- unit_test_macro_age_binning.yaml

version: 2

unit_tests:
  - name: simple_grouping
    model: macro_test_age_binning
    description: Ensure correct age group labels are returned
    given:
      - input: this
        rows:
          - { age: 18 }
          - { age: 24 }
    expect:
      rows:
        - { age: 18, age_group: 'val_1' }
        - { age: 24, age_group: 'val_2' }

```

The unit test does compile and provides an output, however for some reason the table is not being overwritten by the input that I am defining in my unit test and instead keeps the NULL values that I have when initializing the testing model. This is the output of the compiled query for unit testing where I can see that it isn’t overriding the fixture data…

```auto
with
     __dbt__ cte__macro_test_age_binning as (

-- Fixture for macro_test_age_binning
select

    cast(18 as INTEGER)
 as age, cast(null as character varying(256)) as age_group
union all
select

    cast(24 as INTEGER)
 as age, cast(null as character varying(256)) as age_group
), dummy_data as (
        select
        null::int as age
    )
select
    dummy_data.age,
    case
        when dummy_data.age between 10 and 19 then 'val_1'
        when dummy_data.age between 20 and 29 then 'val_2'
        ...
    end as age_group
from dummy_data

```

### Stop Gap Workaround

One change that I did do was to create another dummy called `macro_test_age_binning_initialize` where I instead built the initial NULL data

```auto
# macro_test_age_binning_initialize.sql

select
    null::int as age

```

and edited my model dedicated to testing the macro and changed my unit test with the following

```auto
# macro_test_age_binning.sql

select
    age,
    {{ age_binning('age') }} as age_group
from {{ ref('macro_test_age_binning_initialize') }}

```

```auto
- unit_test_macro_age_binning.yaml
version: 2

unit_tests:
  - name: simple_grouping
    model: macro_test_age_binning
    description: Ensure correct age group labels are returned
    given:
      - input: ref('macro_test_age_binning_initialize') -- Changed here
        rows:
          - { age: 18 }
          - { age: 24 }
    expect:
      rows:
        - { age: 18, age_group: 'val_1' }
        - { age: 24, age_group: 'val_2' }

```

With these changes, the unit test now is able to utilize the fixed dataset described in the unit test. However this workaround seems very dubious and makes testing a bit more complex with adding an extra model just to make this work..

### My Question

Is this workaround actually necessary?  
Is it considered a bad practice to create dedicated models for testing macros like this?  
Is there a cleaner or more idiomatic way to test macros that return expressions rather than full models?

Thanks in advance!
