name: dbt-helpers-nullable-testing description: Implement and use Nullable Infrastructure adapters for mock-free testing. Use when writing unit tests for core logic, implementing infrastructure adapters, or setting up test fixtures.
dbt-helpers-nullable-testing
Purpose
To ensure fast, deterministic, and reliable testing without the brittleness of standard mocking libraries. This skill implements the "Functional Core, Imperative Shell" philosophy using the Nullable Infrastructure pattern.
Core Principles
- No standard mocks: Avoid
unittest.mockfor infrastructure (I/O, DB, CLI). - Nullable Adapters: Real implementations with an "off switch" or in-memory substitute.
- Internal State Tracking: Adapters should track their output/actions for state-based assertions.
Implementation Patterns
1. In-memory Substitutes
- Use DuckDB in-memory for catalog clients.
- Use a dictionary-based
MemoryFileSystemfor file I/O. - Use a list-based
BufferEmitterfor CLI output.
2. Nullable Constructor
Each infrastructure class should provide a .create_null() factory method:
class CatalogClient(ABC):
@classmethod
def create_null(cls, metadata: dict = None):
return NullCatalogClient(metadata)
Instructions
When writing unit tests
- Use the
.create_null()version of the adapter. - Provide pre-configured state to the nullable adapter (e.g.,
CatalogClient.create_null(tables=[...])). - Assert on the results of the logic, or check the adapter's internal state if necessary.
When implementing a new adapter
- Define the interface (Protocol/ABC) in the SDK.
- Implement the production version.
- Implement the Nullable version (usually in the same file or a
testing.pymodule).