tree: 53aa647cec73b88252fed015351235b5820d4673
  1. conftest.py
  2. decorated_functions.py
  3. my_functions.py
  4. README.md
  5. requirements.txt
  6. test_ad_hoc_module.py
  7. test_decorated_functions.py
  8. test_driver.py
  9. test_my_functions.py
examples/testing/README.md

Testing Apache Hamilton code

This is the runnable companion to the Testing Hamilton code how-to. It shows that Hamilton functions are normal Python -- so the standard pytest patterns you already know apply, including when decorators are involved.

The example covers the four cases from issue #1044:

  1. Unit-testing plain functions -- test_my_functions.py
  2. Unit-testing decorated functions -- test_decorated_functions.py
  3. Integration-testing the DAG with inputs= and overrides= -- test_driver.py
  4. In-memory modules with ad_hoc_utils.create_temporary_module -- test_ad_hoc_module.py

File organization

FilePurpose
my_functions.pyA small marketing dataflow (no decorators).
decorated_functions.pyThe same style of dataflow, using @tag, @parameterize and @extract_columns.
test_my_functions.pyUnit tests that import and call functions directly.
test_decorated_functions.pyUnit + driver-level tests for the decorated module.
test_driver.pyEnd-to-end tests using Builder().with_modules(...).build() plus inputs= and overrides=.
test_ad_hoc_module.pyBuilds a module from inline-defined functions for self-contained tests.
conftest.pyAdds this folder to sys.path so import my_functions works under pytest.

Running the tests

pip install -r requirements.txt
pytest

You should see all tests pass. Each test file is independently runnable:

pytest test_my_functions.py -v
pytest test_driver.py -v

What to take away

  • A Hamilton function is just a Python function. Testing it does not require building a Driver.
  • Decorators (@tag, @parameterize, @extract_columns, ...) leave the underlying callable intact. Direct function calls still work; the decorator changes how Hamilton wires the function into the DAG, not what the function computes.
  • For integration tests, Builder().with_modules(...).build() is the canonical entry point. Use inputs= to inject test data at the DAG inputs and overrides= to short-circuit intermediate nodes when you want to assert on downstream logic in isolation.
  • Need to test inline -- e.g. for a regression test or a custom materializer -- without a .py file on disk? Use hamilton.ad_hoc_utils.create_temporary_module.

If you have questions, or need help with this example, join us on Slack.