Files
BSN-Chatsystem/bsn-agent-testaufgabe.md
T

6.1 KiB
Raw Blame History

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 — 1520 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

  1. Funktion validate_rating(wert: int) -> bool:

    • Prüft, ob eine Bewertung zwischen 1 und 10 liegt
    • Wirft ValueError bei ungültigen Werten
    • Deutscher Docstring (Google-Style) mit Args, Returns, Raises
  2. Funktion berechne_durchschnitt(bewertungen: list[int]) -> float | None:

    • Berechnet den Durchschnitt einer Bewertungsliste
    • Gibt None zurück, wenn die Liste leer ist
    • Jede Bewertung wird vorher mit validate_rating() geprüft
    • Vollständige Typ-Annotationen (auch -> None wo nötig)
  3. Konstante MAX_BEWERTUNG = 10 (UPPER_SNAKE_CASE)

  4. 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 Implementierung
  • test_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 (110).

    Returns:
        True, wenn die Bewertung gültig ist.

    Raises:
        ValueError: Wenn die Bewertung außerhalb 110 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 110).

    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)