Hinweise zu den QuickCheck-Tests

Wenn Ihre Übung korrekt hochgeladen wurde, werden die Programme in Ihrer Abgabe automatisch durch unser System kompiliert und mit Quickcheck überprüft. Das Ergebnis finden Sie per Link in unserem Übungssystem.

Die Übersicht

Wenn Ihre Lösung erfolgreich kompiliert, erhalten Sie einen Überblick über sämtliche Testfälle und ob diese korrekt und innerhalb des Zeitlimits durchgelaufen sind.

Beispielübersicht

Erwartunsgemäß bedeutet grün, dass ein Test fehlerfrei durchgelaufen ist, während rot einen Fehler kennzeichnet. In den Kästen unter den Testnamen sind weitere Hinweise bzw. Systemmeldungen angegeben (siehe Erklärungen unten). Generell können Sie die Meldungen bei bestandenen Tests ignorieren; bei nicht bestandenen Tests hingegen liefern sie wertvollen Hinweise, wie man das Problem beheben kann.

In diesem Beispiel sind für Aufgabe 1 zwei Tests korrekt durchgelaufen und ein Test hat ein falsches Ergebnis geliefert. In Aufgabe 2 hat der Test zu lange gebraucht, wohingegen in Aufgabe 3 eine Behauptung nicht korrekt bewiesen worden ist.

Mögliche Testergebnisse

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. Benachrichtigen Sie uns bitte in diesem Fall, damit wir das Problem beheben können.

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]

(Die Meldung, den fehlgeschlagenen Test mit --quickcheck-replay zu reproduzieren, können Sie getrost ignorieren.)

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.

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.

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.

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).