fix: QC-Ratings aus 7 älteren Artikeln entfernt (CHECK 10)
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
# 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
|
||||
|
||||
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 (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)
|
||||
```
|
||||
|
||||
```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>
|
||||
Reference in New Issue
Block a user