First commit

This commit is contained in:
Johan
2025-12-17 13:29:14 +01:00
commit cc50161771
43 changed files with 3665 additions and 0 deletions

110
tests/etape6_resolver_v2.py Normal file
View File

@@ -0,0 +1,110 @@
"""
Tests de validation pour l'Étape 6 : Optimisation du Resolver GraphQL (Version 2)
Objectif :
1. Vérifier que le resolver V2 récupère bien le LLM du contexte.
2. Vérifier que le resolver V2 utilise `is_field_requested` pour
passer les bons booléens au service V2.
Prérequis :
- Les TODOs de `app/graphql/resolvers/analyze_movie_v2.py` sont complétés.
- Le champ `analyzeMovie` de `app/graphql/queries.py` est mis à jour
pour utiliser le resolver V2.
"""
import pytest
import strawberry
from unittest.mock import AsyncMock, MagicMock, patch
@pytest.fixture
def mock_info():
"""Fixture pour un objet Info de Strawberry."""
mock_llm_instance = MagicMock(name="MockLLM")
info = MagicMock()
info.context = {"llm": mock_llm_instance}
return info
@pytest.mark.asyncio
async def test_resolver_v2_partial_request(mocker, mock_info):
"""
Teste le resolver V2 avec une requête partielle.
Vérifie qu'il passe les bons drapeaux au service.
"""
# 1. Mocker les dépendances (le service V2 et le helper is_field_requested)
# On mock le service V2 pour espionner ses arguments
mock_service = AsyncMock(return_value={
"id": "1",
"aiSummary": "Service Result",
"aiOpinionSummary": None,
"aiBestGenre": None,
"aiTags": None
})
mocker.patch('app.graphql.resolvers.analyze_movie_v2.analyze_movie', mock_service)
# On mock 'is_field_requested' pour simuler une requête partielle
def mock_is_field_requested(info, field_name):
if field_name == "aiSummary":
return True
return False
mocker.patch('app.graphql.resolvers.analyze_movie_v2.is_field_requested', mock_is_field_requested)
# 2. Appel du resolver
from app.graphql.resolvers.analyze_movie_v2 import analyze_movie_by_id
await analyze_movie_by_id(
movie_id=strawberry.ID("1"),
info=mock_info
)
# 3. Assertions
# Vérifie que le service a été appelé avec les bons drapeaux
mock_service.assert_called_once_with(
movie_id="1",
ai_summary=True,
ai_opinion_summary=False,
ai_best_genre=False,
ai_tags=False,
llm=mock_info.context["llm"] # Vérifie que le LLM du contexte est bien passé
)
@pytest.mark.asyncio
async def test_resolver_v2_full_request(mocker, mock_info):
"""
Teste le resolver V2 avec une requête complète.
"""
# 1. Mocker les dépendances
# [CORRECTION] Le mock doit retourner un dictionnaire complet
# pour que MovieAnalysis(**analysis_data) fonctionne.
mock_service_return = {
"id": "1",
"aiSummary": "Mock summary",
"aiOpinionSummary": "Mock opinion",
"aiBestGenre": "Mock genre",
"aiTags": ["mock", "tag"]
}
mock_service = AsyncMock(return_value=mock_service_return)
mocker.patch('app.graphql.resolvers.analyze_movie_v2.analyze_movie', mock_service)
# Simule une requête complète
mocker.patch('app.graphql.resolvers.analyze_movie_v2.is_field_requested', return_value=True)
# 2. Appel du resolver
from app.graphql.resolvers.analyze_movie_v2 import analyze_movie_by_id
await analyze_movie_by_id(
movie_id=strawberry.ID("1"),
info=mock_info
)
# 3. Assertions
# Vérifie que le service a été appelé avec TOUS les drapeaux à True
mock_service.assert_called_once_with(
movie_id="1",
ai_summary=True,
ai_opinion_summary=True,
ai_best_genre=True,
ai_tags=True,
llm=mock_info.context["llm"]
)