**Dies ist eine alte Version des Dokuments!**
Testing
Wird ein Software-Projekt etwas grösser, so steigt die Wahrscheinlichkeit, irgendwo einen Fehler einzubauen, rasant an. Zum Beispiel lösen wir irgendwo im Code ein Problem, aber vergessen, dass die Änderung an einer anderen Stelle zu einem neuen Bug führt.
Um dem entgegenzuwirken, schreiben wir Tests: Separater Code, der den eigentlichen Produktiv-Code ausführt und sicherstellt, dass die Resultate unseren Erwartungen entsprechen.
Unit Testing in Python
Ein Unit Test überprüft die Funktionsweise eines Moduls ($\approx$ einer Python-Datei).
Sorting Example
Wir haben folgenden Python-Code, den wir testen wollen:
- sorting.py
def is_sorted(liste): index = 0 while index < len(liste) - 1: a = liste[0] b = liste[1] if b < a: return False index = index + 1 return True
Aber stimmt der Code auch wirklich? Wir schreiben einen ersten Test, wobei Tests normalerweise in Dateien mit dem Präfix test_
gespeichert werden:
- test_sorting.py
from sorting import * assert is_sorted(['Apfel', 'Birne', 'Zwetschge']) assert not is_sorted(['Birne', 'Apfel', 'Zwetschge'])
Die assert
Anweisung (ohne Klammern!) überprüft, ob der folgende Ausdruck wahr ist, also zu True
evaluiert. Die erste Zeile überprüft, ob die Liste als sortiert erkannt wird, die zweite, ob herausgefunden wird, dass die Liste nicht sortiert ist.
Wir führen den Test aus mit python test_sorting.py
- scheint alles in Ordnung zu sein.
Test Driven Development
Du kriegst einen Bug-Report eines erbosten Benutzers deiner sorting
Bibliothek. Die Liste ['Apfel', 'Zwetschge', 'Birne']
sei fälschlicherweise als sortiert erkannt worden! Natürlich könnten wir jetzt direkt das Problem im Code suchen - aber wer stellt sicher, dass das Problem nicht plötzlich wieder auftaucht? Genau, ein Test.
Im Test-Driven-Development suchen wir nicht zuerst den Fehler, sondern schreiben zuerst einen neuen Test-Case, der den Fehler reproduziert (also beim Test-Durchlauf fehlschlägt). Erst dann flicken wir den fehlerhaften Code, bis alle Tests wieder grün sind.
Aufgabe A
Schreibe einen Test-Case für den rapportierten Fehler. Flicke anschliessend die is_sorted
Funktion, bis alle Tests wieder durchlaufen.
Integration Tests
Integration Tests sind eine Stufe höher als die Unit Tests angesiedelt; sie testen das Zusammenspiel von mehreren Modulen oder eines ganzen Programms. Weil diese meist länger dauern als Unit Tests, werden Sie seltener ausgeführt.
Test Coverage
Die Test-Coverage (oder Testabdeckung) ist ein Wert zwischen 0 und 100%, der beschreibt, wie gross der Anteil unseres Codes ist, der von den Tests überprüft wird.
Test Automation
Statt nach jeder Änderung die Tests laufen zu lassen, kann dies auch automatisiert werden: z.B. werden bei jedem Commit die Tests ausgeführt und der Commit erst ins Repository genommen, wenn sie erfolgreich sind. Auf github kann dies über Continuous Integration und github actions erreicht werden.