Home

03 Brownfield-Übungen: KI-gestütztes Testen in Locust

exercise python locust testing coverage brownfield

Überblick

In dieser Übung nutzen Sie KI-Unterstützung, um Tests zu schreiben, die die Code-Coverage verbessern — in einem echten Open-Source-Projekt: Locust, einem Python-Lasttest-Framework. Sie arbeiten in Teams von 3-5 Studierenden. Alle Teams arbeiten am selben Paket (Paket A — kleine, in sich geschlossene Python-Hilfsfunktionen), sodass Sie danach die Ansätze der Teams untereinander vergleichen können.

Die Kernregel: Jeder KI-Prompt, der Code erzeugt, bekommt einen eigenen Commit, der sowohl die Codeänderungen als auch einen Tagebucheintrag enthält. Dies zwingt Sie, in kleinen, dokumentierten Schritten zu arbeiten — genau so funktioniert KI-gestützte Entwicklung in der Praxis.

Falls Sie die Locust Exploration-Übung bereits absolviert haben, sind die Setup-Schritte 1-6 möglicherweise schon erledigt. Überfliegen Sie sie und setzen Sie dort fort, wo Sie aufgehört haben.

Prompts selbst gestalten: Sie sollen Ihre eigenen Prompts für die KI formulieren. Denken Sie an Vorlesung 2 — From Copy-Paste to Crafted Prompts und wenden Sie an, was Sie über strukturiertes, kontextreiches Prompting gelernt haben. Ihr Tagebuch soll die verwendeten Prompts und Ihre Iterationen dokumentieren.


Setup

  1. Repository klonen — wir arbeiten mit einer Lehrkopie in unserer Kursorganisation:

    git clone https://github.com/hs-aalen-software-engineering/locust.git
    cd locust
    
  2. Abhängigkeiten installieren:

    uv sync
    

    Falls dies fehlschlägt, häufige Ursachen sind: uv nicht installiert (docs.astral.sh/uv), fehlendes Python 3.10+ oder gevent-Build-Fehler unter Windows. Nutzen Sie Ihr KI-Tool zum Debuggen.

    Achtung: Auch ausgereifte Open-Source-Projekte haben manchmal unvollständige Dependency-Dateien. Wenn uv sync — oder später pytest — über ein fehlendes Modul meckert, sind Sie möglicherweise auf einen echten Bug in pyproject.toml / uv.lock gestoßen. Beheben Sie es lokal mit uv add <modul> und halten Sie den Fund im Tagebuch fest. Das ist ein legitimer Beitrag.

  3. Pre-Commit Hooks aktivieren — diese führen bei jedem Commit ruff (Linter + Formatter) aus:

    pip install pre-commit
    pre-commit install
    
  4. pytest verifizieren — führen Sie die Paket-A-Testdatei aus, um Ihr Setup zu bestätigen:

    uv run pytest locust/test/test_util.py -x -q
    

    Wenn das durchläuft, ist Ihr Setup in Ordnung.

  5. Feature-Branch erstellen:

    git checkout -b feature/<team-name>-util-coverage
    # Beispiel: feature/team3-util-coverage
    
  6. Tagebuch-Ordner erstellen:

    mkdir -p diary/feature/<team-name>-util-coverage
    

So arbeiten Sie: Commits und Tagebuch

Die Ein-Prompt-ein-Commit-Regel

Jeder Prompt, der Code erzeugt, bekommt einen eigenen Commit, der sowohl die Codeänderungen als auch den Tagebucheintrag enthält. So sieht ein Zyklus aus:

  1. Sie schreiben einen Prompt und geben ihn der KI.
  2. Die KI generiert Code. Sie bewerten ihn, bearbeiten ihn, führen Tests aus.
  3. Sie schreiben einen Tagebucheintrag (z.B. 002-coverage-memoize.md) mit Prompt, Tool, Modell und Anzahl der Iterationen.
  4. Sie führen git add für sowohl die Testdatei als auch die Tagebuchdatei aus.
  5. Sie committen: git commit -m "[diary] 002 — Tests for util/cache.py memoize()"

Das ist der Arbeitsablauf für jede Aufgabe in dieser Übung. Keine Ausnahmen.

Vorlage für Tagebucheinträge

Jeder Tagebucheintrag folgt diesem Format:

# NNN — Short Title

**Date**: YYYY-MM-DD
**Tool**: [Claude Code / GitHub Copilot / ...]
**Model**: [model name]
**Iterations**: [number of follow-up prompts]

## Prompt

**YYYY-MM-DD HH:MM**

[The full prompt text as given to the AI.]

Ordnerstruktur des Tagebuchs

diary/feature/<team-name>-util-coverage/
├── 001-onboarding.md
├── 002-coverage-memoize.md
├── 003-coverage-retry.md
└── 004-coverage-calc-distribution.md

Warum das wichtig ist

Das Tagebuch IST der Nachweis KI-gestützter Arbeit. Ein PR mit guten Tests, aber ohne Tagebucheinträge bekommt null Punkte für das Kriterium “PR- und Tagebuchqualität” (25 % der Note). Der Prozess zählt mehr als die Politur. Ein gut dokumentierter Versuch mit Korrekturen und Reflexionen ist mehr wert als ein perfektes Ergebnis ohne Nachweis, wie Sie dorthin gelangt sind.


Definition of Done

Jeder PR ist vollständig, wenn:

  1. Alle bestehenden Tests bestehen (keine Regressionen)
  2. Neue Tests prüfen tatsächliches Verhalten (nicht nur Zeilenabdeckung)
  3. Der Code den Linter besteht — aktivieren Sie Pre-Commit Hooks (pre-commit install) oder verwenden Sie die ruff VS Code Extension, oder führen Sie uv run ruff check . && uv run ruff format --check manuell aus
  4. Commit-Nachrichten klar und aussagekräftig sind
  5. Tagebucheinträge den vollständigen Prozess dokumentieren

Paket-A-Anleitung: util/cache.py — Schritt für Schritt

Arbeiten Sie diese Anleitung als Team durch. Sie führt eine Datei komplett durch, damit alle den vollständigen Ablauf sehen, bevor Sie sich aufteilen und die restlichen Dateien selbstständig bearbeiten.

Dateifokus: locust/util/cache.py — der memoize()-Dekorator (derzeit nur 10 % Zeilenabdeckung).

Schritt 1: Aktuelle Coverage messen

Führen Sie den Coverage-Befehl aus — beachten Sie die zwei --cov-report-Flags. Der html-Report ist derjenige, auf den es ankommt:

uv run pytest locust/test/test_util.py locust/test/test_log.py locust/test/test_taskratio.py \
  --cov=locust/util --cov=locust/log \
  --cov-report=term-missing --cov-report=html -q

Die Terminal-Tabelle zeigt pro Datei einen Cover-Prozentsatz und Missing-Zeilennummern. Das ist für einen schnellen Überblick nützlich — aber der HTML-Report ist der Ort, an dem Sie wirklich lernen, was fehlt:

  1. Öffnen Sie htmlcov/index.html im Browser (einfach doppelklicken, oder start htmlcov/index.html unter Windows).
  2. Klicken Sie auf locust/util/cache.py.
  3. Nicht abgedeckte Zeilen sind rot markiert. Teilweise abgedeckte Branches sind gelb. Abgedeckte Zeilen sind grün.

Halten Sie diese Seite in einem Tab offen. Sie kommen nach jedem Testlauf hierher zurück.

Schritt 2: Den zu testenden Code lesen

Öffnen Sie locust/util/cache.py. Suchen Sie den memoize()-Dekorator. Es ist ein reiner Python-Dekorator ohne externe Abhängigkeiten — Sie verstehen ihn in 5 Minuten.

Worauf Sie achten sollten:

Sie müssen den Code gut genug verstehen, um beurteilen zu können, ob die Tests der KI korrekt sind. Wenn Sie diesen Schritt überspringen und der KI-Ausgabe blind vertrauen, werden Sie Tests erhalten, die plausibel aussehen, aber nichts Sinnvolles testen.

Schritt 3: Tests für memoize() schreiben

Nutzen Sie jetzt Ihr KI-Tool. Schreiben Sie einen Prompt, der Folgendes enthält:

Verwenden Sie keinen vagen Prompt. Hier ist ein Beispiel, was Sie NICHT tun sollten:

Generate tests to get 100% coverage on cache.py.

Warum das schlecht ist: Die Optimierung auf Coverage-Prozente erzeugt bedeutungslose Tests. Die KI generiert Tests, die die Funktion mit trivialen Eingaben aufrufen und True asserten — technisch werden Zeilen abgedeckt, aber nichts wird verifiziert. Ein Test, der keinen echten Bug fängt, ist wertlos, egal wie viele Zeilen er “abdeckt.”

Seien Sie stattdessen konkret darüber, welches Verhalten jeder Test verifizieren soll. Die KI produziert besseren Code, wenn Ihr Prompt das Was und Warum beschreibt, nicht nur “mach die Zahl größer.”

Schritt 4: Die KI-Ausgabe bewerten

Bevor Sie einen generierten Test akzeptieren, stellen Sie sich drei Fragen:

  1. Testet er ein spezifisches Verhalten? Ein Test, der cached_fn() aufruft und assertet, dass der Rückgabewert nicht None ist, testet nichts Nützliches.
  2. Würde dieser Test fehlschlagen, wenn ein echter Bug eingeführt würde? Wenn jemand die Timeout-Logik so brechen würde, dass Cache-Einträge nie ablaufen, würde dieser Test das erkennen?
  3. Prüfen die Assertions das Richtige? Die Assertions sollten den Inhalt des Rückgabewerts oder den Seiteneffekt verifizieren (z.B. dass die zugrundeliegende Funktion die erwartete Anzahl an Malen aufgerufen wurde), nicht nur den Typ.

Löschen Sie jeden Test, den Sie nicht erklären können. Besser 3 aussagekräftige Tests als 8 oberflächliche.

Schritt 5: Tests ausführen und Coverage prüfen

Führen Sie zuerst den schnellen Testbefehl aus, um zu verifizieren, dass nichts kaputt ist:

uv run pytest locust/test/test_util.py -x -q

Dann führen Sie den Coverage-Befehl aus Schritt 1 erneut aus:

uv run pytest locust/test/test_util.py locust/test/test_log.py locust/test/test_taskratio.py \
  --cov=locust/util --cov=locust/log \
  --cov-report=term-missing --cov-report=html -q

Aktualisieren Sie htmlcov/index.html im Browser und klicken Sie erneut auf cache.py. Die vorher roten Zeilen sollten jetzt grün sein. Falls einige noch rot sind, zeigt Ihnen der HTML-Report genau welche — gehen Sie zurück zu Schritt 3 und fügen Sie Tests für diese Fälle hinzu.

Schritt 6: Commit mit Tagebucheintrag

Schreiben Sie Ihren Tagebucheintrag — zum Beispiel diary/feature/<team-name>-util-coverage/002-coverage-memoize.md — unter Verwendung der Vorlage aus dem Tagebuch-Abschnitt oben. Dokumentieren Sie den vollständigen Prompt, das Tool, das Modell und wie viele Iterationen nötig waren.

Dann committen Sie beide Dateien zusammen:

git add locust/test/test_util.py diary/feature/<team-name>-util-coverage/002-coverage-memoize.md
git commit -m "[diary] 002 — Tests for util/cache.py memoize()"

Sowohl die Testdatei ALS AUCH die Tagebuchdatei sind im selben Commit. Das ist die Regel.

Schritt 7: Jetzt bearbeiten Sie die restlichen Dateien selbstständig

Die obige Anleitung hat Ihnen das Muster gezeigt. Wenden Sie die Schritte 2-6 selbstständig auf jede der folgenden Dateien an. Jede Datei bekommt ihren eigenen Tagebucheintrag und ihren eigenen Commit.

Datei 2: locust/util/exception_handler.py — retry()-Dekorator

Aktuelle Coverage: 54 %. Nur der Happy Path ist getestet — die Retry- und Fehlerpfade sind nicht abgedeckt.

Schreiben Sie Tests für:

Ziel: 54 % → nahe 100 %.

Datei 3: locust/user/inspectuser.py — _calc_distribution()

Aktuelle Coverage: 60 %. Reine Berechnung mit einfachen User-Klassen-Stubs.

Schreiben Sie Tests für:

Ziel: 60 % → ~80 %.

Nutzen Sie nach jeder Runde den HTML-Coverage-Report, um zu bestätigen, dass die vorher roten Zeilen grün werden.

Schritt 8: Pull Request erstellen

Pushen Sie Ihren Branch und erstellen Sie einen PR gegen master:

git push -u origin feature/<team-name>-util-coverage

Ihre PR-Beschreibung sollte enthalten:

## Coverage

| Datei | Vorher | Nachher |
|-------|--------|---------|
| util/cache.py | 10 % | 98 % |
| util/exception_handler.py | 54 % | 96 % |
| user/inspectuser.py | 60 % | 81 % |

Geschätzte Gesamtzeit: 60-75 Minuten mit KI-Unterstützung.


Liefergegenstände

Reichen Sie einen PR gegen master pro Team ein, der Folgendes enthält:


Bewertungsmatrix

Kriterium Gewichtung Hervorragend Ausreichend Unzureichend
Coverage-Verbesserung 25 % Alle drei Dateien erreichen die Zielprozentwerte, gemessen am HTML-Report Zwei von drei Zielen erreicht, eines teilweise Weniger als zwei Ziele erreicht
Testqualität 35 % Tests verifizieren Verhalten mit aussagekräftigen Assertions, Randfälle eingeschlossen, würden echte Bugs fangen Tests verifizieren grundlegendes Verhalten, wenige Randfälle Tests sind reine Zeilenabdecker — hohe Coverage, geringer Wert
Keine Regressionen 15 % Alle bestehenden Tests bestehen, Linter besteht (uv run ruff check .), keine Änderungen an bestehenden Testdateien Alle Tests bestehen, kleinere Lint-Probleme Bestehende Tests fehlgeschlagen oder Lint-Fehler
PR- und Tagebuchqualität 25 % Klare PR-Beschreibung, vollständiges Tagebuch mit Prompts, abgelehnte/akzeptierte KI-Ausgaben dokumentiert, Coverage-Zahlen enthalten Grundlegende PR-Beschreibung, teilweises Tagebuch Fehlende PR-Beschreibung oder Tagebuch

Kurzreferenz

Schneller Testbefehl

uv run pytest locust/test/test_util.py locust/test/test_log.py locust/test/test_taskratio.py -x -q

Laufzeit: ~8 Sekunden.

Coverage-Befehl (mit HTML-Report)

uv run pytest locust/test/test_util.py locust/test/test_log.py locust/test/test_taskratio.py \
  --cov=locust/util --cov=locust/log \
  --cov-report=term-missing --cov-report=html -q

Danach htmlcov/index.html öffnen.

Hinweis zu vorbestehenden Testfehlern

Einige Tests in der vollständigen Suite schlagen aufgrund von Umgebungsunterschieden fehl (SSL-Zertifikate, Config-Dateipfade, Windows-spezifische Probleme). Keiner davon befindet sich in den Paket-A-Testdateien. Falls Sie einen Fehler in test_log.py:test_greenlet_exception_logger antreffen, handelt es sich um ein bekanntes vorbestehendes Problem — ignorieren Sie es.


Tipps

© 2026 Dominik Müller   •  Powered by Soopr   •  Theme  Moonwalk