Wir wissen, dass das Schreiben von JUnit- Tests einen bestimmten Pfad durch Ihren Code zeigt.
Einer meiner Mitarbeiter kommentierte:
Das manuelle Schreiben von Komponententests ist Proof By Example .
Er kam aus dem Hintergrund von Haskell, das Tools wie Quickcheck und die Fähigkeit hat, über das Programmverhalten mit Typen nachzudenken .
Seine Implikation war, dass es viele andere Kombinationen von Eingaben gibt, die von dieser Methode nicht ausprobiert werden und für die Ihr Code nicht getestet wurde.
Meine Frage ist: Schreiben Sie Unit-Tests manuell anhand eines Beispiels?
unit-testing
junit
Falkenauge
quelle
quelle
Antworten:
Wenn Sie nach dem Zufallsprinzip Eingaben zum Testen auswählen, ist es möglicherweise möglich, dass Sie einen logischen Proof By Example-Irrtum ausüben.
Aber gute Unit-Tests machen das nie. Stattdessen befassen sie sich mit Bereichen und Randfällen.
Wenn Sie beispielsweise Komponententests für eine Absolutwertfunktion schreiben würden, die eine Ganzzahl als Eingabe akzeptiert, müssten Sie nicht jeden möglichen Eingabewert testen, um zu beweisen, dass der Code funktioniert. Um einen umfassenden Test zu erhalten, benötigen Sie nur fünf Werte: -1, 0, 1 sowie die Max- und Min-Werte für die Eingabe-Ganzzahl.
Diese fünf Werte testen jeden möglichen Bereich und Kantenfall der Funktion. Sie müssen nicht jeden anderen möglichen Eingabewert testen (dh jede Zahl, die der Integer-Typ darstellen kann), um ein hohes Konfidenzniveau zu erhalten, dass die Funktion für alle Eingabewerte funktioniert.
quelle
int foo(int x) { return 1234/(x - 100); }
. Beachten Sie auch, dass Sie (je nachdem, was Sie testen) möglicherweise sicherstellen müssen, dass eine ungültige ("außerhalb des Bereichs") Eingabe korrekte Ergebnisse zurückgibt (z. B. dass "find_thing (thing)" korrekt eine Art "nicht gefunden" -Status zurückgibt wenn das Ding nicht gefunden wurde).-Inf
,Inf
,NaN
,1e-100
,-1e-100
,-0
,2e200
... Ich würde lieber nicht alle manuell zu tun.Jeder Softwaretest ist wie "Proof By Example", nicht nur Unit-Tests mit einem Tool wie JUnit. Und das ist keine neue Weisheit, es gibt ein Zitat von Dijkstra aus dem Jahr 1960, das im Wesentlichen dasselbe sagt:
(Ersetzen Sie einfach die Wörter "Shows" durch "Beweise"). Dies gilt jedoch auch für Tools, die zufällige Testdaten generieren. Die Anzahl der möglichen Eingaben für eine reale Funktion ist in der Regel um Größenordnungen größer als die Anzahl der Testfälle, die unabhängig von der Methode zur Erzeugung dieser Fälle erstellt und anhand eines erwarteten Ergebnisses im Zeitalter des Universums überprüft werden können Selbst wenn man ein Generator-Tool zum Erzeugen vieler Testdaten verwendet, gibt es keine Garantie, den einen Testfall nicht zu verpassen, der einen bestimmten Fehler hätte erkennen können.
Zufällige Tests können manchmal einen Fehler aufdecken, der von manuell erstellten Testfällen übersehen wurde. Im Allgemeinen ist es jedoch effizienter, Tests für die zu testende Funktion sorgfältig zu erstellen und sicherzustellen, dass eine vollständige Code- und Zweigabdeckung mit möglichst wenigen Testfällen erhalten wird. Manchmal ist es eine praktikable Strategie, manuell und zufällig generierte Tests zu kombinieren. Darüber hinaus muss bei der Verwendung von Zufallstests darauf geachtet werden, dass die Ergebnisse reproduzierbar sind.
Manuell erstellte Tests sind also keineswegs schlechter als zufällig generierte Tests, oft im Gegenteil.
quelle
Das manuelle Schreiben von Tests ist "Beweis durch Beispiel". Dies gilt jedoch auch für QuickCheck und in begrenztem Umfang für Typsysteme. Alles, was keine direkte formale Überprüfung ist, wird in den Informationen über Ihren Code eingeschränkt sein. Stattdessen muss man über den relativen Wert von Ansätzen nachdenken.
Generative Tests wie QuickCheck eignen sich sehr gut, um einen großen Bereich von Eingaben zu erfassen. Es ist auch viel besser, um Randfälle anzugehen als manuelle Tests: Generative Testbibliotheken werden damit mehr Erfahrung haben als Sie. Auf der anderen Seite erzählen sie nur von Invarianten, nicht von bestimmten Ausgaben. Um zu validieren, dass Ihr Programm die richtigen Ergebnisse liefert, benötigen Sie noch einige manuelle Tests, um dies tatsächlich zu überprüfen
foo(bar) = baz
.quelle