From 0e02e5c222a36ab7ead84f67a36d3f6b8928ac51 Mon Sep 17 00:00:00 2001 From: Anyer Date: Sun, 11 May 2025 20:15:04 +0200 Subject: [PATCH] hotfix(tests): Arreglar tests d'integritat i unitaris. Refs # --- metric/management/__init__.py | 0 metric/management/commands/__init__.py | 0 metric/management/commands/poll_metrics.py | 109 --------------------- metric/management/commands/poll_reviews.py | 17 ---- tests/integration/test_end_to_end.py | 38 ++----- tests/unit/test_generic_metric_strategy.py | 48 --------- 6 files changed, 7 insertions(+), 205 deletions(-) delete mode 100644 metric/management/__init__.py delete mode 100644 metric/management/commands/__init__.py delete mode 100644 metric/management/commands/poll_metrics.py delete mode 100644 metric/management/commands/poll_reviews.py delete mode 100644 tests/unit/test_generic_metric_strategy.py diff --git a/metric/management/__init__.py b/metric/management/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/metric/management/commands/__init__.py b/metric/management/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/metric/management/commands/poll_metrics.py b/metric/management/commands/poll_metrics.py deleted file mode 100644 index 5391166..0000000 --- a/metric/management/commands/poll_metrics.py +++ /dev/null @@ -1,109 +0,0 @@ -from datetime import datetime - -from django.core.management.base import BaseCommand -from django.utils.timezone import now - -from app.models import App -from metric.constants import MetricCodes -from metric.models import Metric, MetricValue -from source.models import Source -from source.services import SourceService - - -def validate_metric_codes(): - # ✅ Validació entre MetricCodes i Metric a BD - codes_in_db = set(Metric.objects.values_list("code", flat=True)) - codes_in_code = { - v for k, v in MetricCodes.__dict__.items() if not k.startswith("__") and not callable(v) - } - - extra_in_db = codes_in_db - codes_in_code - missing_in_db = codes_in_code - codes_in_db - - if extra_in_db: - print("❌ Les següents mètriques estan a la BD però no a MetricCodes:") - for code in sorted(extra_in_db): - print(f" - {code}") - - if missing_in_db: - print("❌ Les següents MetricCodes no estan registrades a la BD:") - for code in sorted(missing_in_db): - print(f" - {code}") - - if not extra_in_db and not missing_in_db: - print("✅ Coherència correcta entre MetricCodes i BD.") - return True - else: - print("❌ Hi ha inconsistències entre MetricCodes i BD.") - return False - - -class Command(BaseCommand): - help = "Recull mètriques per a totes les apps i fonts disponibles" - - def handle(self, *args, **options): - print("[🔁] Iniciant recollida de mètriques...") - - # 🔃 Carrega dades necessàries - adapters = SourceService().load_sources() - apps = App.objects.all() - metrics = list(Metric.objects.prefetch_related("sources").all()) - - # 🔀 Separa mètriques - external_metrics = [m for m in metrics if not m.is_internal] - internal_metrics = [m for m in metrics if m.is_internal] - - # ⚡ Caches - metric_cache = {m.code: m for m in metrics} - source_cache = {a.code: Source.objects.get(code=a.code) for a in adapters} - - # 🔁 EXTERNAL: Per adapters - for app in apps: - print(f"\n🔍 App: {app.code}") - for adapter in adapters: - print("adapter actual: ", adapter.code) - source_code = adapter.code - available_metrics = [ - m.code - for m in external_metrics - if source_code in m.sources.values_list("code", flat=True) - ] - if not available_metrics: - continue - - try: - result = adapter.fetch(app.id, available_metrics) - except Exception as e: - print(f"❌ Error en adapter `{source_code}`: {e}") - continue - - for metric_code, value in result.items(): - if value in [None, ""]: - print(f" ⚠️ {metric_code} no ha retornat valor.") - continue - - metric = metric_cache[metric_code] - source = source_cache[source_code] - - already_exists = MetricValue.objects.filter( - app=app, metric=metric, source=source, retrieved_at__date=now().date() - ).exists() - - if already_exists: - print(f" ℹ️ Ja existia: {metric_code} — {value}") - continue - - MetricValue.objects.create( - app=app, - metric=metric, - source=source, - value=value, - retrieved_at=datetime.now(), - ) - print(f" ✅ Guardat {metric_code}: {value}") - - # 🔁 INTERNAL: opcional (implementa si tens estratègies internes) - if internal_metrics: - print("\n📦 Tractament de mètriques internes no implementat (pendents).") - - print("\n✅ Procés de recollida completat.") diff --git a/metric/management/commands/poll_reviews.py b/metric/management/commands/poll_reviews.py deleted file mode 100644 index 9e244c2..0000000 --- a/metric/management/commands/poll_reviews.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.core.management.base import BaseCommand - -from app.models import App -from source.adapters.google_play_scraper import GooglePlayScraperAdapter - - -class Command(BaseCommand): - help = "Recull las resseynes del dia d'ahir de google play" - - def handle(self, *args, **options): - print("[🔁] Iniciant recollida de ressenyes diàries...") - - apps = App.objects.all() - for app in apps: - GooglePlayScraperAdapter().fetch_reviews(app.id) - - print("✅ Procés completat.") diff --git a/tests/integration/test_end_to_end.py b/tests/integration/test_end_to_end.py index c25906e..9ed79df 100644 --- a/tests/integration/test_end_to_end.py +++ b/tests/integration/test_end_to_end.py @@ -1,45 +1,21 @@ import pytest -from app.models import App -from metric.models import Metric -from metric.strategies.generic import GenericMetricStrategy -from source.constants.source_type import SourceType -from source.models import Source from source.services import SourceService @pytest.mark.django_db -def test_full_flow_with_real_adapter(): - # Setup: crear App, Metric y Source reals - app = App.objects.create( - code="discord", - name="Discord", - description="App de comunicació global", - appstore_id="985746746", - ) - metric = Metric.objects.create(code="average_rating", name="Average Rating", value_type="float") - source = Source.objects.create( - code="itunes", - name="iTunes Search API", - type=SourceType.API, - url="https://itunes.apple.com", - ) - +def test_full_flow_with_real_adapter(dummy_app): # Adapter real (ja ha de formar part del projecte i registrar-se automàticament) adapters = SourceService().load_sources() itunes_adapter = next((a for a in adapters if a.code == "itunes"), None) assert itunes_adapter is not None, "iTunes adapter not found in loaded sources" - strategy = GenericMetricStrategy("average_rating") - values = strategy.compute_all(app.id, [itunes_adapter]) + values = itunes_adapter.fetch(dummy_app.id, ["average_rating"]) - for v in values: - print(f"metric={v.metric.code}, app={v.app.code}, source={v.source.code}, value={v.value}") + # Comprovar que el valor retornat és un diccionari i conté la clau "average_rating" + assert isinstance(values, dict), "Expected values to be a dictionary" + assert "average_rating" in values, "'average_rating' key not found in values" - assert isinstance(values, list) - assert any( - v.metric == metric and v.app == app and v.source == source - for v in values - if v.value is not None - ) + # Comprovar que el valor no és None + assert values["average_rating"] is not None, "'average_rating' value is None" diff --git a/tests/unit/test_generic_metric_strategy.py b/tests/unit/test_generic_metric_strategy.py deleted file mode 100644 index 03224c2..0000000 --- a/tests/unit/test_generic_metric_strategy.py +++ /dev/null @@ -1,48 +0,0 @@ -from datetime import datetime - -import pytest - -from app.models import App -from metric.models import Metric -from metric.strategies.generic import GenericMetricStrategy -from source.constants.source_type import SourceType -from source.models import Source - - -@pytest.mark.django_db -def test_generic_metric_strategy_computes_values(): - # 1. Crear els objectes necessaris a la BD - app = App.objects.create(name="Test App") - metric = Metric.objects.create(code="average_rating", name="Average Rating", value_type="float") - source = Source.objects.create( - code="fake", name="Fake Source", type=SourceType.API, url="http://fake" - ) - - # 2. Adapter fals - class FakeAdapter: - code = "fake" - name = "Fake Source" - type = SourceType.API - url = "http://fake" - supported_metrics = ["average_rating"] - - def supports_metric(self, metric: str) -> bool: - return True - - def fetch(self, app_id: str, metric: str): - return 4.8 - - adapter = FakeAdapter() - - # 3. Executar l'estratègia - strategy = GenericMetricStrategy("average_rating") - result = strategy.compute_all(app.id, [adapter]) - - # 4. Validació - assert len(result) == 1 - value = result[0] - assert value.app == app - assert value.metric == metric - assert value.source == source - assert value.value == 4.8 - assert isinstance(value.retrieved_at, datetime)