Add Integration Test
Create a new integration test for dbt-autofix. Integration tests verify that the refactor tool correctly transforms dbt projects.
Philosophy: Test-Driven Development
Integration tests document DESIRED behavior, not current behavior.
- For bug fixes: Create a test that reproduces the bug, with expected output showing the correct behavior
- For feature requests: Create a test that specifies what the feature should do
- Tests should FAIL initially, then PASS once the fix/feature is implemented
This approach:
- Serves as a specification for the work
- Prevents regressions
- Automatically validates when the implementation is complete
Using GOLDIE_UPDATE: Run with GOLDIE_UPDATE=1 to understand current behavior, but don't blindly accept it as the expected output. Manually craft the _expected files to reflect what the behavior should be.
Arguments
$ARGUMENTS- The test project name (e.g.,config_quoted_strings)
Running a single test:
uv run pytest "tests/integration_tests/test_full_dbt_projects.py::test_project_refactor[project_<name>]" -v
Example for a project named config_quoted_strings:
uv run pytest "tests/integration_tests/test_full_dbt_projects.py::test_project_refactor[project_config_quoted_strings]" -v
Naming guidance: Use descriptive names that explain what the test covers, not issue numbers. For example:
config_quoted_strings(notissue_221)python_model_meta_config(notissue_220)jinja_unmatched_endif
The name becomes project_<name> in the test projects directory.
Test Structure
Each integration test requires 3 artifacts in tests/integration_tests/dbt_projects/:
project_<name>/- Input dbt project (before refactor)- Minimum:
dbt_project.yml+ model files inmodels/
- Minimum:
project_<name>_expected/- Expected output (after refactor)- Mirror of input with the DESIRED transformations applied
project_<name>_expected.stdout- Expected JSON log output- One JSON object per line documenting refactors that SHOULD be applied
Steps to Follow
Step 1: Gather Information
Reference the README for the authoritative list of deprecations: README.md
Discover existing test projects to see patterns and avoid duplication:
ls tests/integration_tests/dbt_projects/ | grep -v _expected
Ask the user:
- What deprecation, bug, or behavior is being tested?
- Is there a GitHub issue number to reference?
- Does this test need special flags?
--behavior-changemode--semantic-layermode
Step 2: Understand Current Behavior (Optional)
Run with GOLDIE_UPDATE=1 to see what the tool currently does:
GOLDIE_UPDATE=1 uv run pytest "tests/integration_tests/test_full_dbt_projects.py::test_project_refactor[project_<name>]" -v
Note: Do NOT commit the auto-generated _expected files from GOLDIE_UPDATE without review. They reflect current behavior, not necessarily desired behavior. Manually craft the expected output to reflect what the behavior should be.
Step 3: Create Project Structure
tests/integration_tests/dbt_projects/
├── project_<name>/
│ ├── dbt_project.yml
│ └── models/
│ └── <model>.sql (or .py for Python models)
├── project_<name>_expected/
│ ├── dbt_project.yml
│ └── models/
│ └── <model>.sql
└── project_<name>_expected.stdout
Minimal dbt_project.yml:
name: '<test name>'
version: '1.0.0'
config-version: 2
profile: 'default'
model-paths: ["models"]
Step 4: Create Test Models (Input)
Create model files that demonstrate the behavior being tested. The input should contain the pattern that triggers the deprecation/refactor.
Step 5: Create Expected Output (Desired Behavior)
Manually create the _expected files showing what the output SHOULD be after the fix/feature is implemented. Do NOT just copy current behavior.
Step 6: Create Expected stdout
Write the JSON log output that SHOULD be produced. Each line is a JSON object:
{"mode": "applied", "file_path": "...", "refactors": [{"deprecation": "...", "log": "..."}]}
{"mode": "complete"}
Step 7: Handle Special Modes (if needed)
If the test requires --behavior-change or --semantic-layer, add an entry to the dicts in tests/integration_tests/test_full_dbt_projects.py:
project_dir_to_behavior_change_mode["project_<name>"] = True
# or
project_dir_to_semantic_layer_mode["project_<name>"] = True
Step 8: Verify Test Behavior
# Should fail (or xfail) if feature not implemented
uv run pytest "tests/integration_tests/test_full_dbt_projects.py::test_project_refactor[project_<name>]" -v
# Should pass once feature is implemented
Golden File Tips
GOLDIE_UPDATE=1shows current behavior - use for understanding, not as source of truth- The
file_pathkey is ignored during comparison (paths don't need to match) - Blank lines are ignored in file comparisons
- The
_expectedsuffix must match exactly - Include trailing newlines in files
Example Workflows
Bug Fix (quoted strings causing errors)
- Create
project_config_quoted_strings/with a model containing the problematic quoted string - Create
project_config_quoted_strings_expected/showing correct handling (no error, proper transformation) - Test fails initially (bug exists)
- Fix the bug
- Test passes (bug fixed)
Feature Request (Python model custom config access)
- Create
project_python_model_meta_config/with a Python model usingdbt.config.get("custom_key") - Create
project_python_model_meta_config_expected/showing the Python code updated todbt.config.get("meta").get("custom_key") - Test fails initially (feature not implemented)
- Implement feature
- Test passes (feature complete)