Files
ss-tools/.ai/knowledge/test_import_patterns.md

3.0 KiB

Backend Test Import Patterns

Problem

The ss-tools backend uses relative imports inside packages (e.g., from ...models.task import TaskRecord in persistence.py). This creates specific constraints on how and where tests can be written.

Key Rules

1. Packages with __init__.py that re-export via relative imports

Example: src/core/task_manager/__init__.py imports .manager.persistencefrom ...models.task (3-level relative import).

Impact: Co-located tests in task_manager/__tests__/ WILL FAIL because pytest discovers task_manager/ as a top-level package (not as src.core.task_manager), and the 3-level from ... goes beyond the top-level.

Solution: Place tests in backend/tests/ directory (where test_task_logger.py already lives). Import using from src.core.task_manager.XXX import ... which works because backend/ is the pytest rootdir.

2. Packages WITHOUT __init__.py:

Example: src/core/auth/ has NO __init__.py.

Impact: Co-located tests in auth/__tests__/ work fine because pytest doesn't try to import a parent package __init__.py.

3. Modules with deeply nested relative imports

Example: src/services/llm_provider.py uses from ..models.llm import LLMProvider and from ..plugins.llm_analysis.models import LLMProviderConfig.

Impact: Direct import (from src.services.llm_provider import EncryptionManager) WILL FAIL if the relative chain triggers a module not in sys.path or if it tries to import beyond root.

Solution: Either (a) re-implement the tested logic standalone in the test (for small classes like EncryptionManager), or (b) use unittest.mock.patch to mock the problematic imports before importing the module.

Working Test Locations

Package __init__.py? Relative imports? Co-located OK? Test location
core/task_manager/ YES from ...models.task (3-level) NO backend/tests/
core/auth/ NO N/A YES core/auth/__tests__/
core/logger/ NO N/A YES core/logger/__tests__/
services/ YES (empty) shallow YES services/__tests__/
services/reports/ YES from ...core.logger NO (most likely) backend/tests/ or mock
models/ YES shallow YES models/__tests__/

Safe Import Patterns for Tests

# In backend/tests/test_*.py:
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

# Then import:
from src.core.task_manager.models import Task, TaskStatus
from src.core.task_manager.persistence import TaskPersistenceService
from src.models.report import TaskReport, ReportQuery

Plugin ID Mapping (for report tests)

The resolve_task_type() uses hyphenated plugin IDs:

  • superset-backupTaskType.BACKUP
  • superset-migrationTaskType.MIGRATION
  • llm_dashboard_validationTaskType.LLM_VERIFICATION
  • documentationTaskType.DOCUMENTATION
  • anything else → TaskType.UNKNOWN