This document outlines the testing approach and structure for the Dylan package.
The testing framework is being set up with a focus on unit tests that don't require the actual Claude provider. This allows for faster and more reliable testing without triggering actual provider calls.
The current branch has implemented these changes:
- Fixed import errors in test files
- Updated package structure to ensure proper imports
- Simplified subprocess and exit command tests
- Temporarily skipped tests that would trigger real Claude provider calls
- Added support for mocking provider behavior
Dylan uses a vertical slice architecture for testing, with tests located close to the modules they test:
dylan/
├── conftest.py # Main conftest with shared fixtures
├── tests/ # Tests for core CLI
│ ├── __init__.py
│ └── test_cli.py # Tests for the main CLI application
├── utility_library/
├── shared/ # Shared components
│ ├── tests/ # Tests for shared utilities
│ ├── __init__.py
│ ├── test_exit_command.py
│ └── test_subprocess_utils.py
├── dylan_review/
│ ├── tests/
│ ├── __init__.py
│ ├── conftest.py # Review-specific fixtures
│ ├── test_dylan_review_cli.py
│ └── test_dylan_review_runner.py
├── dylan_pr/
│ ├── tests/
│ ├── ...
└── ...
Tests are run using pytest with UV:
# Run all tests (includes skipped tests)
uv run pytest
# Run tests for a specific module
uv run pytest dylan/utility_library/dylan_review/tests/
# Run tests with coverage report
uv run pytest --cov=dylan
# Run a specific test file
uv run pytest dylan/utility_library/dylan_review/tests/test_dylan_review_runner.py
# Run tests without skipped tests
uv run pytest -k "not skip"- Test individual functions and classes in isolation
- Located in each vertical's tests directory
- Naming:
test_<module>_<function>.py
- Test interactions between components
- Located in each vertical's tests directory
- Prefix:
test_integration_*.py
- Test CLI commands end-to-end
- Located in the root tests directory
- Limited use of mocks - simulate real usage
- Prefix:
test_functional_*.py
mock_claude_provider: Mocks the Claude Code provider for testingtemp_output_dir: Creates a temporary directory for test outputscli_runner: Provides a Typer CLI test runnermock_git_repo: Creates a mock git repository structuremock_git_operations: Mocks common git commands
Each vertical slice has its own fixtures in its conftest.py file.
mock_git_diff: Mock git diff outputsample_review_report: Sample review report for testingmock_review_runner: Mock for the review runner module
mock_git_branch_info: Mock git branch informationmock_github_api: Mock GitHub API responsesmock_gh_cli: Mock GitHub CLI command responsesmock_pr_runner: Mock for the PR runner module
- External dependencies (git, gh, claude) are mocked
- File operations use temporary directories
- Internal modules use fixture-based dependency injection
- Unit tests use fine-grained mocking
- Integration tests use coarser-grained mocking
When adding new functionality:
- Create unit tests for new modules in the appropriate tests directory
- Update/add fixtures in the relevant conftest.py
- Add integration tests for interactions with other components
- Run the full test suite before submitting changes
For new vertical slices:
- Create a tests directory within the vertical
- Add a vertical-specific conftest.py
- Implement appropriate unit, integration, and functional tests
Code coverage is tracked using pytest-cov:
# Generate coverage report
uv run pytest --cov=dylan --cov-report=term
# Generate HTML coverage report
uv run pytest --cov=dylan --cov-report=htmlThe test suite runs automatically on:
- Pull requests to develop and main branches
- Direct pushes to develop and main branches
All tests must pass for PRs to be merged.