Der Schnitt aus CLAUDE.md ist durchgehalten: - Fetch (deterministisch, kein LLM): marktguru-Adapter mit geprüftem Ortsbezug (zipCode), Wochen-Cache, robots.txt-Respekt, ehrlicher Regel-4- Abbruch bei fehlendem Beleg statt Krücke. - Kategorisierung (einziger LLM-Ort): geschlossene Liste + Daten-Integrität als Code erzwungen; austauschbar via Protokoll (OpenRouter/Anthropic), mit Drosselung/Retry und ehrlichem Abbruch. - FastAPI-Web-UI als dünne Schicht: Modellauswahl (Liste/Suche/Refresh), Live-Fortschritt, gruppierte Ergebnisse mit Filtern, Ergebnis-Cache. - 36 Tests gegen die Architektur-Regeln (kein Auffüllen, Abbruch, Integrität, geschlossene Liste, Unsicherheit, Schnitt) und die Web-Schicht. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
1.5 KiB
Python
54 lines
1.5 KiB
Python
"""Test-Doubles -- halten die Tests offline (kein Netz, kein LLM, kein Schlüssel)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import date, datetime
|
|
from typing import Callable
|
|
|
|
from angebote.modell import Angebot
|
|
from angebote.quellen.basis import Ort
|
|
|
|
|
|
class FakeQuelle:
|
|
"""Adapter-Double: liefert vorgegebene Angebote, deckt-Flag, optional Fehler."""
|
|
|
|
def __init__(self, name, angebote=None, *, deckt=True, fehler=None):
|
|
self.name = name
|
|
self._angebote = list(angebote or [])
|
|
self._deckt = deckt
|
|
self._fehler = fehler
|
|
|
|
def deckt_ab(self, ort: Ort) -> bool:
|
|
return self._deckt
|
|
|
|
def hole(self, ort: Ort):
|
|
if self._fehler is not None:
|
|
raise self._fehler
|
|
return list(self._angebote)
|
|
|
|
|
|
class FakeKategorisierer:
|
|
"""Kategorisierer-Double: ruft eine reine Funktion posten->antworten auf."""
|
|
|
|
def __init__(self, fn: Callable[[list[dict]], list[dict]]):
|
|
self._fn = fn
|
|
|
|
def klassifiziere(self, posten: list[dict]) -> list[dict]:
|
|
return self._fn(posten)
|
|
|
|
|
|
def beispiel_angebot(titel="Butter", **kw) -> Angebot:
|
|
"""Belegtes Angebot mit Default-Pflichtfeldern; einzeln überschreibbar."""
|
|
daten = dict(
|
|
titel=titel,
|
|
haendler="REWE",
|
|
quelle="test:fixture",
|
|
abgerufen_am=datetime(2026, 6, 1, 8, 0, 0),
|
|
preis=1.49,
|
|
marke="Markenbutter",
|
|
menge="250 g",
|
|
gueltig_von=date(2026, 6, 1),
|
|
gueltig_bis=date(2026, 6, 7),
|
|
)
|
|
daten.update(kw)
|
|
return Angebot(**daten)
|