- Add async context manager to NFOService wrapping TMDBClient + ImageDownloader - Add TMDBClient.__del__ warning when session leaks - Log exc_info on session recreation for traceback visibility - Document async-with usage in docs/DEVELOPMENT.md and docs/TESTING.md - Add unit tests covering leak detection, context-manager cleanup, and connector-closed warning Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
4.5 KiB
4.5 KiB
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)
- Security audit procedures (see 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
- Testing Philosophy
- Test pyramid approach
- Quality gates
- 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/)
- Unit Tests (
- Test Structure and Naming
- File naming conventions
- Test function naming
- Test class organization
- Running Tests
- pytest commands
- Running specific tests
- Verbose output
- Coverage reports
- Fixtures and Conftest
- Shared fixtures
- Database fixtures
- Mock services
- Mocking Guidelines
- What to mock
- Mock patterns
- External service mocks
Mocking the Download Queue
Use MockQueueRepository for testing download queue functionality:
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_itemusesitem.idas key (must be set before calling)- Suitable for unit tests only (no persistence)
Mocking aiohttp Sessions
When testing code that uses aiohttp.ClientSession:
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.closedisTrueafter context manager exits - Mock
__aenter__and__aexit__for response context managers - Set
closed = Falseon mock session for unclosed warning tests
- Coverage Requirements
- CI/CD Integration
- Writing Good Tests
- Arrange-Act-Assert pattern
- Test isolation
- Edge cases
- Common Pitfalls to Avoid