6.1 KiB
6.1 KiB
BSN Coding Standards — Agenten-Testaufgabe
Ziel: Prüfen, ob ein lokaler Agent (z. B. Qwen 3.6) die BSN Coding Standards selbstständig einhält. Die Aufgabe ist bewusst klein — 15–20 Minuten für einen Agenten.
Aufgabe: Spiel-Bewertungs-Utility
Schreibe ein Python-Modul game_rating.py, das Brettspiel-Bewertungen validiert
und einen Durchschnitt berechnet. Das Modul wird später in einer Flask-API verwendet.
Anforderungen
-
Funktion
validate_rating(wert: int) -> bool:- Prüft, ob eine Bewertung zwischen 1 und 10 liegt
- Wirft
ValueErrorbei ungültigen Werten - Deutscher Docstring (Google-Style) mit Args, Returns, Raises
-
Funktion
berechne_durchschnitt(bewertungen: list[int]) -> float | None:- Berechnet den Durchschnitt einer Bewertungsliste
- Gibt
Nonezurück, wenn die Liste leer ist - Jede Bewertung wird vorher mit
validate_rating()geprüft - Vollständige Typ-Annotationen (auch
-> Nonewo nötig)
-
Konstante
MAX_BEWERTUNG= 10 (UPPER_SNAKE_CASE) -
Tests in
test_game_rating.py:- Test für gültige Bewertung
- Test für ungültige Bewertung (ValueError)
- Test für Durchschnitt mit mehreren Werten
- Test für leere Liste (None)
- Test für ungültigen Wert in der Liste (ValueError)
Was der Agent BEACHTEN muss (BSN Standards)
| Regel | Woran erkennbar |
|---|---|
| Typ-Annotationen | Jede Funktion hat -> mit korrektem Typ |
X | None |
-> float | None, NICHT Optional[float] |
| Deutsche Docstrings | Google-Style, auf Deutsch |
snake_case |
Funktionen und Variablen |
UPPER_SNAKE_CASE |
Konstante |
| Keine Secrets | Kein API-Key, kein Passwort im Code |
| Test-Namen | test_<was>_<erwartung> |
Erfolgskriterien (Automatisch prüfbar)
# 1. Linting + Formatierung
ruff check game_rating.py test_game_rating.py --fix
ruff format game_rating.py test_game_rating.py
# 2. Typ-Prüfung
mypy game_rating.py test_game_rating.py
# 3. Tests
pytest test_game_rating.py -v
# Alle drei müssen GRÜN sein.
Abgabe
Der Agent soll zwei Dateien erstellen:
game_rating.py— die Implementierungtest_game_rating.py— die Tests
Erwartete Lösung (Referenz — NICHT dem Agenten zeigen!)
⚠️ Nur zum Nachschlagen — nicht vorab zeigen
# game_rating.py
"""Brettspiel-Bewertungs-Utility.
Validiert Bewertungen und berechnet Durchschnittswerte.
"""
MAX_BEWERTUNG = 10
def validate_rating(wert: int) -> bool:
"""Prüft, ob eine Bewertung im gültigen Bereich liegt.
Args:
wert: Die zu prüfende Bewertung (1–10).
Returns:
True, wenn die Bewertung gültig ist.
Raises:
ValueError: Wenn die Bewertung außerhalb 1–10 liegt.
"""
if not isinstance(wert, int):
raise ValueError(f"Bewertung muss eine Ganzzahl sein, nicht {type(wert).__name__}")
if wert < 1 or wert > MAX_BEWERTUNG:
raise ValueError(
f"Bewertung {wert} ist ungültig. Erlaubt: 1–{MAX_BEWERTUNG}"
)
return True
def berechne_durchschnitt(bewertungen: list[int]) -> float | None:
"""Berechnet den Durchschnitt einer Bewertungsliste.
Args:
bewertungen: Liste von Bewertungen (je 1–10).
Returns:
Der Durchschnittswert oder None, wenn die Liste leer ist.
Raises:
ValueError: Wenn eine Bewertung ungültig ist.
"""
if not bewertungen:
return None
for wert in bewertungen:
validate_rating(wert)
return sum(bewertungen) / len(bewertungen)
# test_game_rating.py
"""Tests für das Spiel-Bewertungs-Utility."""
import pytest
from game_rating import MAX_BEWERTUNG, validate_rating, berechne_durchschnitt
class TestValidateRating:
"""Tests für validate_rating()."""
def test_valid_rating_returns_true(self) -> None:
"""Gibt True für eine gültige Bewertung zurück."""
assert validate_rating(5) is True
def test_min_rating_returns_true(self) -> None:
"""Gibt True für die minimale Bewertung (1) zurück."""
assert validate_rating(1) is True
def test_max_rating_returns_true(self) -> None:
"""Gibt True für die maximale Bewertung (10) zurück."""
assert validate_rating(MAX_BEWERTUNG) is True
def test_zero_raises_valueerror(self) -> None:
"""Wirft ValueError bei Bewertung 0."""
with pytest.raises(ValueError, match="ungültig"):
validate_rating(0)
def test_above_max_raises_valueerror(self) -> None:
"""Wirft ValueError bei Bewertung > 10."""
with pytest.raises(ValueError, match="ungültig"):
validate_rating(11)
def test_negative_raises_valueerror(self) -> None:
"""Wirft ValueError bei negativer Bewertung."""
with pytest.raises(ValueError, match="ungültig"):
validate_rating(-1)
def test_non_int_raises_valueerror(self) -> None:
"""Wirft ValueError bei nicht-Integer-Wert."""
with pytest.raises(ValueError, match="Ganzzahl"):
validate_rating(3.5) # type: ignore[arg-type]
class TestBerechneDurchschnitt:
"""Tests für berechne_durchschnitt()."""
def test_single_rating_returns_same(self) -> None:
"""Gibt den Wert selbst bei einer einzelnen Bewertung zurück."""
assert berechne_durchschnitt([7]) == 7.0
def test_multiple_ratings_returns_average(self) -> None:
"""Berechnet den korrekten Durchschnitt mehrerer Bewertungen."""
assert berechne_durchschnitt([6, 8, 10]) == 8.0
def test_empty_list_returns_none(self) -> None:
"""Gibt None bei leerer Liste zurück."""
assert berechne_durchschnitt([]) is None
def test_invalid_rating_in_list_raises_valueerror(self) -> None:
"""Wirft ValueError, wenn die Liste eine ungültige Bewertung enthält."""
with pytest.raises(ValueError, match="ungültig"):
berechne_durchschnitt([5, 0, 7])
def test_float_result(self) -> None:
"""Gibt Float zurück, auch wenn der Durchschnitt keine ganze Zahl ist."""
result = berechne_durchschnitt([5, 8])
assert result == 6.5
assert isinstance(result, float)