Files
Aniworld/docs/TESTING.md
Lukas 6aec2a1733 docs: add SetupService to architecture, update changelog and testing docs
- ARCHITECTURE.md: add setup_service.py to services list
- CHANGELOG.md: add Unreleased section with folder scan key resolution fix
- TESTING.md: add SetupService testing section with example tests
2026-06-05 20:42:26 +02:00

4.3 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

  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:

from src.server.models.download import DownloadItem, EpisodeIdentifier

class MockQueueRepository:
    def __init__(self):
        self._items: Dict[str, DownloadItem] = {}

Testing SetupService

SetupService handles series key resolution from folder names during library setup. Test file: tests/unit/test_setup_service.py.

Key methods tested:

  • _extract_year_from_folder_name() — parses (YYYY) suffix
  • _extract_title_from_folder_name() — strips year suffix
  • _resolve_key_via_search() — resolves provider key via fuzzy title matching
@pytest.mark.asyncio
async def test_returns_key_when_single_exact_match(self):
    """Search returns 1 result with same name → returns key."""
    mock_series_app = AsyncMock()
    mock_series_app.search.return_value = [
        {'title': 'Attack on Titan', 'link': '/anime/stream/attack-on-titan'}
    ]

    with patch('src.server.services.setup_service.get_series_app', return_value=mock_series_app):
        result = await SetupService._resolve_key_via_search("Attack on Titan")

    assert result == 'attack-on-titan'

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.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
  1. Coverage Requirements
  2. CI/CD Integration
  3. Writing Good Tests
    • Arrange-Act-Assert pattern
    • Test isolation
    • Edge cases
  4. Common Pitfalls to Avoid