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

200 lines
6.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
```bash
# 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!)
<details>
<summary>⚠️ Nur zum Nachschlagen — nicht vorab zeigen</summary>
```python
# 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)
```
```python
# 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)
```
</details>