Hinweise zu den QuickCheck-Tests

Wenn Ihre Übung an der richtigen Stelle hochgeladen wurde, werden die Programme in Ihrer Abgabe automatisch durch unser System kompiliert und mit Quickcheck überprüft. Das Ergebnis finden Sie entweder auf dem in Ihrem Benutzerverzeichnis auf dem Übungsserver als output_n.log oder auf unserer Statusseite.

Wenn Ihre Lösung erfolgreich kompiliert (und Ihre Lösung nicht so langsam ist, dass die Tests nicht innerhalb des Zeitlimits durchlaufen), steht am Anfang das Logs zunächst eine Übersicht, wie die Tests für jede Aufgabe ausgefallen sind. Steht dort überall GOOD, so hat Ihre Lösung alle unsere Tests bestanden. Andernfalls steht dort die Zahl der fehlgeschlagenen Tests. Welche Tests genau fehlgeschlagen sind, steht weiter unten in der Ausgabe. Die Tests sind gruppiert nach den Aufgaben auf dem Übungsblatt. Machen Sie sich die Mühe zu verstehen, warum Ihre Tests fehlschlagen. Was testet der Test? Haben Sie die Aufgabe falsch verstanden oder ist es nur ein ein kleiner Programmierfehler? Häufig untersuchen die Tests, ob spezielle Randfälle richtig behandelt wurden — wenn Sie die Testergebnisse genau anschauen, vermeiden Sie unnütz Punkte zu verschenken.

Im folgenden finden Sie einige Hinweise zum Verständnis der Testergebnisse. Zu jedem Test wird eine kurze Beschreibung und das Testergebnis ausgegeben. Im Optimalfall sieht das so aus:

Der Heuhaufen ist leer
+++ OK, passed 100 tests.

Diese Ausgabe bedeutet, dass Ihr Code diesen Test auf 100 verschiedenen Eingaben bestanden hat. Die Anzahl der getesten Eingaben hängt nur von unserem Test ab und kann variieren. Steht dort eine 1, heißt das, dass ein konkretes Beispiel getestet wurde. Für Sie genauso gut ist der folgende Fall:

*** Gave up! Passed only 39 tests.
Teilsequenzen plus ein Element in 'xs' sind Quasi-Teilsequenzen

Auch hier hat ihr Code alle Tests bestanden. Das Gave up! heißt nicht, dass Ihr Code zu langsam war, sondern deutet auf ein Defizit unseres Tests hin: Hier hat QuickCheck mit vertretbarem Aufwand nur 39 Eingaben erzeugen können, die die Vorbedingungen unseres Tests erfüllen. Den meisten dürfte folgendes bekannt vorkommen:

subseq: first argument empty
*** Failed! Exception: 'Prelude.undefined' (after 1 test): 
""

Hier ist der Test mit der Eingabe "" fehlgeschlagen, da eine Exception aufgetreten ist. Prelude.undefined heißt, dass undefined zur Definition der Funktion verwendet wurde. Ein anderer häufiger Fehler ist Non-exhaustive patterns in function, wenn Ihre Funktion mit einer Eingabe aufgerufen wurde, die zu keinem der für die Funktion gegebenen Regeln passt. Interessanter sind die Fälle, bei denen Ihre Funktion ein falsches Ergebnis geliefert hat:

concat (irregularChunks ks xs) == xs for sum ks = length xs
*** Failed! Falsifiable (after 1 test): 
"9"
[1]

Hier ist der Test mit der Beschreibung length of result == length ks fehlgeschlagen. Als Eingaben hat er für den fehlgeschlagenen Test die Parameter "w" und [1] bekommen. Leider ensprechen die Eingaben für den Test nicht unbedingt den Eingaben für die Funktion. Wo sinnvoll, bemühen wir uns zwar, dies zu erreichen, dies ist aber aus technischer Sicht nicht immer machbar. Dennoch sollte es Ihnen möglich sein, aus der Testbeschreibung und den Typen der Eingabe zu rekonstruieren, was an Ihrer Implementierung falsch ist.

Beispielsweise gehört der obenstehende Test zu einer Aufgabe, in der eine Funktion irregularChunks :: [Int] -> [a] -> [[a]] zu implementieren war. Aus der Testbeschreibung entnehmen Sie, dass es zwei Eingaben (ks und ts) gibt, wobei eine vom Typ [Int] und eine vom Typ [a] sein muss. Daraus können Sie schließen, das irregularChunks [1] "9" aufgerufen wurde.

Ein Sonderfall sind die Tests, die erwarten, dass einer der Testfälle fehlschlägt. Dies ist zum Beispiel dann der Fall, wenn ein Übungsblatt von Ihnen verlangt, eigene QuickCheck-Tests für eine Funktion zu implementieren: Wir testen dann unter anderem, ob Ihre QuickCheck-Tests hilfreich sind, das heißt eine falsche Implementierung der Funktion erkennen können. Die Erwartung ist dann, dass auf mindestens einer der (z.B.) 100 unterschiedlichen Eingaben ihr QuickCheck-Test fehlschlägt. In diesem Fall sehen die Ausgaben wie folgt aus:

+++ OK, failed as expected. Falsifiable (after 1 test): 
Text "\tipsum "

Bei obiger Ausgabe war Ihr Test erfolgreich: Er hat für eine Eingabe (Text "\tipsum ") erkannt, dass die Funktion kein korrektes Ergebnis geliefert hat. Konnte Ihr Test das nicht feststellen, sieht die Ausgabe dagegen so aus:

Detect implementation which only wraps after 50 spaces
*** Failed! Passed 100 tests (expected failure).