# Testing Documentation ## Document Purpose This document describes the testing strategy, guidelines, and practices for the Aniworld project. ### What This Document Contains - **Testing Strategy**: Overall approach to quality assurance - **Test Categories**: Unit, integration, API, performance, security tests - **Test Structure**: Organization of test files and directories - **Writing Tests**: Guidelines for writing effective tests - **Fixtures and Mocking**: Shared test utilities and mock patterns - **Running Tests**: Commands and configurations - **Coverage Requirements**: Minimum coverage thresholds - **CI/CD Integration**: How tests run in automation - **Test Data Management**: Managing test fixtures and data - **Best Practices**: Do's and don'ts for testing ### What This Document Does NOT Contain - Production deployment (see [DEPLOYMENT.md](DEPLOYMENT.md)) - Security audit procedures (see [SECURITY.md](SECURITY.md)) - Bug tracking and issue management - Performance benchmarking results ### Target Audience - Developers writing tests - QA Engineers - CI/CD Engineers - Code reviewers --- ## Sections to Document 1. Testing Philosophy - Test pyramid approach - Quality gates 2. Test Categories - Unit Tests (`tests/unit/`) - Integration Tests (`tests/integration/`) - API Tests (`tests/api/`) - Frontend Tests (`tests/frontend/`) - Performance Tests (`tests/performance/`) - Security Tests (`tests/security/`) 3. Test Structure and Naming - File naming conventions - Test function naming - Test class organization 4. Running Tests - pytest commands - Running specific tests - Verbose output - Coverage reports 5. Fixtures and Conftest - Shared fixtures - Database fixtures - Mock services 6. Mocking Guidelines - What to mock - Mock patterns - External service mocks ### Mocking the Download Queue Use `MockQueueRepository` for testing download queue functionality: ```python from src.server.models.download import DownloadItem, EpisodeIdentifier class MockQueueRepository: def __init__(self): self._items: Dict[str, DownloadItem] = {} async def save_item(self, item: DownloadItem) -> DownloadItem: self._items[item.id] = item return item async def get_item(self, item_id: str) -> Optional[DownloadItem]: return self._items.get(item_id) async def get_all_items(self) -> List[DownloadItem]: return list(self._items.values()) async def set_error(self, item_id: str, error: str) -> bool: if item_id in self._items: self._items[item_id].error = error return True return False async def delete_item(self, item_id: str) -> bool: if item_id in self._items: del self._items[item_id] return True return False async def clear_all(self) -> int: count = len(self._items) self._items.clear() return count ``` **Key points:** - The mock uses in-memory storage, no database required - All async methods are implemented (even if just pass-through) - `save_item` uses `item.id` as key (must be set before calling) - Suitable for unit tests only (no persistence) ### Mocking aiohttp Sessions When testing code that uses `aiohttp.ClientSession`: ```python from unittest.mock import AsyncMock, MagicMock, patch from aiohttp import ClientSession # Mock aiohttp session for testing class MockAiohttpSession: def __init__(self): self.closed = False async def close(self): self.closed = True def get(self, url, **kwargs): mock_response = AsyncMock() mock_response.status = 200 mock_response.json = AsyncMock(return_value={"data": "test"}) mock_response.__aenter__ = AsyncMock(return_value=mock_response) mock_response.__aexit__ = AsyncMock(return_value=None) return mock_response # Use in fixture @pytest.fixture async def mock_tmdb_session(): session = MockAiohttpSession() yield session # Cleanup verification assert session.closed, "Session was not closed" ``` **Key points:** - Always verify `session.closed` is `True` after context manager exits - Mock `__aenter__` and `__aexit__` for response context managers - Set `closed = False` on mock session for unclosed warning tests 7. Coverage Requirements 8. CI/CD Integration 9. Writing Good Tests - Arrange-Act-Assert pattern - Test isolation - Edge cases 10. Common Pitfalls to Avoid