Frage

Ich habe einen Kollegen, der Unit-Tests für Objekte schreibt, die ihre Felder mit Zufallsdaten füllen.Sein Grund dafür ist, dass es einen größeren Testbereich bietet, da viele verschiedene Werte getestet werden, während ein normaler Test nur einen einzigen statischen Wert verwendet.

Ich habe ihm verschiedene Gründe dagegen genannt, die wichtigsten sind:

  • Zufällige Werte bedeuten, dass der Test nicht wirklich wiederholbar ist (was auch bedeutet, dass ein zufälliger Testfehler auf dem Build-Server auftreten und den Build beschädigen kann).
  • Wenn es sich um einen zufälligen Wert handelt und der Test fehlschlägt, müssen wir a) das Objekt reparieren und b) uns zwingen, jedes Mal auf diesen Wert zu testen, damit wir wissen, dass es funktioniert, aber da es zufällig ist, wissen wir nicht, was der Wert war

Ein anderer Kollege fügte hinzu:

  • Wenn ich eine Ausnahme teste, stellen Zufallswerte nicht sicher, dass der Test im erwarteten Zustand endet
  • Zufallsdaten werden zum Ausspülen eines Systems und für Lasttests verwendet, nicht für Unit-Tests

Kann noch jemand weitere Gründe nennen, die ich ihm nennen kann, damit er damit aufhört?

(Oder alternativ: Ist dies eine akzeptable Methode zum Schreiben von Unit-Tests und ich und mein anderer Kollege liegen falsch?)

War es hilfreich?

Lösung

Es gibt einen Kompromiss.Ihr Kollege hat tatsächlich etwas vor, aber ich glaube, er macht es falsch.Ich bin mir nicht sicher, ob völlig zufällige Tests sehr nützlich sind, aber sie sind sicherlich nicht ungültig.

Eine Programm- (oder Einheiten-)Spezifikation ist eine Hypothese, dass es ein Programm gibt, das diese erfüllt.Das Programm selbst ist dann ein Beweis für diese Hypothese.Was Unit-Tests sein sollten, ist ein Versuch, Gegenbeweise zu liefern, um zu widerlegen, dass das Programm gemäß der Spezifikation funktioniert.

Jetzt können Sie die Unit-Tests von Hand schreiben, aber es ist wirklich eine mechanische Aufgabe.Es kann automatisiert werden.Alles, was Sie tun müssen, ist, die Spezifikation zu schreiben, und eine Maschine kann viele, viele Unit-Tests generieren, die versuchen, Ihren Code zu knacken.

Ich weiß nicht, welche Sprache Sie verwenden, aber sehen Sie hier:

Javahttp://functionjava.org/

Scala (oder Java)http://github.com/rickynils/scalacheck

Haskellhttp://www.cs.chalmers.se/~rjmh/QuickCheck/

.NETZ:http://blogs.msdn.com/dsyme/archive/2008/08/09/fscheck-0-2.aspx

Diese Tools nehmen Ihre wohlgeformte Spezifikation als Eingabe und generieren automatisch so viele Unit-Tests, wie Sie möchten, mit automatisch generierten Daten.Sie verwenden „Verkleinerungs“-Strategien (die Sie anpassen können), um den einfachsten möglichen Testfall zu finden, um Ihren Code zu knacken, und um sicherzustellen, dass er die Randfälle gut abdeckt.

Viel Spaß beim Testen!

Andere Tipps

Diese Art der Prüfung wird als a bezeichnet Affentest.Wenn es richtig gemacht wird, können Insekten aus den wirklich dunklen Ecken ausgeräuchert werden.

So gehen Sie auf Ihre Bedenken hinsichtlich der Reproduzierbarkeit ein:Der richtige Weg, dies zu erreichen, besteht darin, die fehlgeschlagenen Testeinträge aufzuzeichnen und einen Komponententest zu generieren, der nach dem sucht ganze Familie des spezifischen Fehlers;und beziehen Sie in den Komponententest die eine spezifische Eingabe (aus den Zufallsdaten) ein, die den anfänglichen Fehler verursacht hat.

Hier gibt es eine Übergangslösung, die einen gewissen Nutzen hat, nämlich Ihr PRNG mit einer Konstante zu versehen.Dadurch können Sie „zufällige“ Daten generieren, die wiederholbar sind.

Persönlich denke ich, dass es Stellen gibt, an denen (konstante) Zufallsdaten beim Testen nützlich sind – nachdem man glaubt, alle sorgfältig durchdachten Aspekte erledigt zu haben, kann die Verwendung von Stimuli aus einem PRNG manchmal andere Ergebnisse bringen.

Im Buch Schöner Code, gibt es ein Kapitel namens „Beautiful Tests“, in dem er eine Teststrategie für das durchgeht Binäre Suche Algorithmus.Ein Absatz heißt „Random Acts of Testing“, in dem er zufällige Arrays erstellt, um den Algorithmus gründlich zu testen.Einiges davon können Sie online bei Google Books lesen. Seite 95, aber es ist ein großartiges Buch, das sich lohnt.

Im Grunde zeigt dies also nur, dass die Generierung zufälliger Daten zum Testen eine praktikable Option ist.

Ein Vorteil für jemanden, der sich die Tests ansieht, besteht darin, dass willkürliche Daten offensichtlich nicht wichtig sind.Ich habe zu viele Tests gesehen, die Dutzende von Daten beinhalteten, und es kann schwierig sein zu sagen, was so sein muss und was zufällig so ist.Z.B.Wenn eine Adressvalidierungsmethode mit einer bestimmten Postleitzahl getestet wird und alle anderen Daten zufällig sind, können Sie ziemlich sicher sein, dass die Postleitzahl der einzig wichtige Teil ist.

Wenn Sie TDD betreiben, würde ich behaupten, dass Zufallsdaten ein ausgezeichneter Ansatz sind.Wenn Ihr Test mit Konstanten geschrieben ist, können Sie nur garantieren, dass Ihr Code für den spezifischen Wert funktioniert.Wenn Ihr Test zufällig auf dem Build-Server fehlschlägt, liegt wahrscheinlich ein Problem mit der Art und Weise vor, wie der Test geschrieben wurde.

Zufällige Daten tragen dazu bei, sicherzustellen, dass zukünftige Refaktorisierungen nicht auf einer magischen Konstante basieren.Wenn Ihre Tests schließlich Ihre Dokumentation sind, bedeutet das Vorhandensein von Konstanten dann nicht, dass es nur für diese Konstanten funktionieren muss?

Ich übertreibe, aber ich füge lieber Zufallsdaten in meinen Test ein, als Zeichen dafür, dass „der Wert dieser Variablen das Ergebnis dieses Tests nicht beeinflussen sollte“.

Ich möchte jedoch sagen, dass es ein Geruch ist, wenn Sie eine Zufallsvariable verwenden und dann Ihren Test basierend auf dieser Variablen aufteilen.

  • Wenn es sich um einen zufälligen Wert handelt und der Test fehlschlägt, müssen wir a) das Objekt reparieren und b) uns zwingen, jedes Mal auf diesen Wert zu testen, damit wir wissen, dass es funktioniert, aber da es zufällig ist, wissen wir nicht, was der Wert war

Wenn Ihr Testfall nicht genau aufzeichnet, was er testet, müssen Sie den Testfall möglicherweise neu codieren.Ich möchte immer Protokolle haben, auf die ich für Testfälle zurückgreifen kann, damit ich genau weiß, was zum Scheitern geführt hat, unabhängig davon, ob statische oder zufällige Daten verwendet wurden.

Ihr Kollege macht es Fuzz-Test, obwohl er nichts davon weiß.Besonders wertvoll sind sie in Serversystemen.

Ich bin für Zufallstests und schreibe sie.Ob sie jedoch in einer bestimmten Build-Umgebung geeignet sind und in welche Testsuiten sie einbezogen werden sollten, ist eine differenziertere Frage.

Lokal ausgeführte (z. B. über Nacht auf Ihrer Entwicklungsbox) zufällige Tests haben sowohl offensichtliche als auch unklare Fehler gefunden.Die obskuren sind so geheimnisvoll, dass ich denke, dass Zufallstests wirklich die einzig realistische Methode waren, um sie aufzuspüren.Als Test nahm ich einen schwer zu findenden Fehler, der durch zufällige Tests entdeckt wurde, und ließ ein halbes Dutzend Crack-Entwickler die Funktion (etwa ein Dutzend Codezeilen) dort überprüfen, wo er auftrat.Keiner konnte es entdecken.

Viele Ihrer Argumente gegen randomisierte Daten klingen nach dem Motto „Der Test ist nicht reproduzierbar“.Ein gut geschriebener randomisierter Test erfasst jedoch den Startwert, der zum Starten des randomisierten Startwerts verwendet wurde, und gibt ihn bei einem Fehler aus.Dies ermöglicht Ihnen nicht nur die manuelle Wiederholung des Tests, sondern auch die einfache Erstellung neuer Tests, die das spezifische Problem testen, indem Sie den Seed für diesen Test fest codieren.Natürlich ist es wahrscheinlich schöner, einen expliziten Test, der diesen Fall abdeckt, von Hand zu programmieren, aber Faulheit hat ihre Vorteile, und dies ermöglicht Ihnen sogar, im Wesentlichen automatisch neue Testfälle aus einem fehlgeschlagenen Startwert zu generieren.

Der einzige Punkt, den Sie ansprechen, über den ich jedoch nicht diskutieren kann, ist, dass dadurch die Build-Systeme beschädigt werden.Die meisten Build- und Continuous-Integration-Tests erwarten, dass die Tests jedes Mal dasselbe tun.Ein Test, der zufällig fehlschlägt, führt also zu Chaos, wenn er zufällig fehlschlägt und mit dem Finger auf Änderungen zeigt, die harmlos waren.

Eine Lösung besteht dann darin, Ihre randomisierten Tests weiterhin als Teil der Build- und CI-Tests auszuführen, aber Führen Sie es mit einem festen Startwert für eine feste Anzahl von Iterationen aus.Daher macht der Test immer das Gleiche, erkundet aber dennoch einen großen Teil des Eingaberaums (wenn Sie ihn für mehrere Iterationen ausführen).

Lokal, z. B. beim Ändern der betreffenden Klasse, können Sie sie für weitere Iterationen oder mit anderen Seeds ausführen.Wenn randomisierte Tests jemals beliebter werden, könnten Sie sich sogar eine bestimmte Reihe von Tests vorstellen, die bekanntermaßen zufällig sind, die mit unterschiedlichen Startwerten (und damit mit zunehmender Abdeckung im Laufe der Zeit) durchgeführt werden könnten und bei denen Fehler nicht dasselbe bedeuten würden als deterministische CI-Systeme (d. h. Ausführungen sind nicht 1:1 mit Codeänderungen verknüpft, sodass Sie nicht mit dem Finger auf eine bestimmte Änderung zeigen, wenn etwas fehlschlägt).

Zu randomisierten Tests gibt es viel zu sagen, vor allem zu gut geschriebenen, also verwerfen Sie sie nicht vorschnell!

Können Sie einige Zufallsdaten einmal generieren (ich meine genau einmal, nicht einmal pro Testlauf) und sie dann in allen Tests danach verwenden?

Ich kann definitiv den Wert erkennen, der darin liegt, zufällige Daten zu erstellen, um die Fälle zu testen, an die Sie noch nicht gedacht haben, aber Sie haben Recht, Unit-Tests zu haben, die zufällig bestehen oder fehlschlagen können, ist eine schlechte Sache.

Sie sollten sich fragen, was das Ziel Ihres Tests ist.
Unit-Tests Dabei geht es um die Überprüfung von Logik, Codefluss und Objektinteraktionen.Durch die Verwendung von Zufallswerten wird versucht, ein anderes Ziel zu erreichen, wodurch der Fokus und die Einfachheit des Tests verringert werden.Dies ist aus Gründen der Lesbarkeit akzeptabel (Generierung von UUID, IDs, Schlüsseln usw.).
Speziell für Unit-Tests kann ich mich nicht erinnern, dass diese Methode einmal erfolgreich Probleme gefunden hat.Aber ich habe viele Determinismusprobleme (in den Tests) gesehen, bei denen versucht wurde, mit Zufallswerten und hauptsächlich mit zufälligen Daten geschickt umzugehen.
Fuzz-Tests sind ein gültiger Ansatz für Integrationstests Und End-to-End-Tests.

Wenn Sie für Ihre Tests zufällige Eingaben verwenden, müssen Sie die Eingaben protokollieren, damit Sie die Werte sehen können.Auf diese Weise können Sie, wenn es einen Randfall gibt, auf den Sie stoßen dürfen Schreiben Sie den Test, um ihn zu reproduzieren.Ich habe die gleichen Gründe von Leuten gehört, die keine zufälligen Eingaben verwenden, aber wenn man erst einmal Einblick in die tatsächlichen Werte hat, die für einen bestimmten Testlauf verwendet werden, ist das kein so großes Problem mehr.

Der Begriff „willkürliche“ Daten ist auch sehr nützlich, um etwas zu kennzeichnen, das existiert nicht wichtig.Uns fallen einige Abnahmetests ein, bei denen viele Lärmdaten vorliegen, die für den jeweiligen Test keine Relevanz haben.

Abhängig von Ihrem Objekt/Ihrer App könnten Zufallsdaten einen Platz im Lasttest haben.Meiner Meinung nach wäre es wichtiger, Daten zu verwenden, die die Randbedingungen der Daten explizit testen.

Wir sind heute gerade darauf gestoßen.ich wollte pseudozufällig (von der Größe her würde es also wie komprimierte Audiodaten aussehen).Ich wollte, dass ich es auch wollte deterministisch.rand() war unter OSX anders als unter Linux.Und wenn ich nicht erneut säe, könnte es sich jederzeit ändern.Also haben wir es so geändert, dass es deterministisch, aber immer noch pseudozufällig ist:Der Test ist genauso wiederholbar wie die Verwendung vorgefertigter Daten (jedoch bequemer geschrieben).

Das war NICHT Testen durch zufällige Brute-Force-Methode über Codepfade.Das ist der Unterschied:immer noch deterministisch, immer noch wiederholbar, immer noch unter Verwendung von Daten, die wie echte Eingaben aussehen, um eine Reihe interessanter Prüfungen für Randfälle in komplexer Logik durchzuführen.Immer noch Unit-Tests.

Gilt das immer noch als zufällig?Lass uns bei einem Bier reden.:-)

Ich kann mir drei Lösungen für das Testdatenproblem vorstellen:

  • Testen Sie mit festen Daten
  • Testen Sie mit Zufallsdaten
  • Generieren Sie Zufallsdaten einmal, und verwenden Sie es dann als Ihre festen Daten

Ich würde es empfehlen alle oben genannten.Das heißt, schreiben Sie wiederholbare Unit-Tests mit einigen Randfällen, die Sie mit Ihrem Gehirn ausgearbeitet haben, und einigen zufälligen Daten, die Sie nur einmal generieren.Schreiben Sie dann eine Reihe randomisierter Tests, die Sie durchführen sowie.

Von den randomisierten Tests sollte niemals erwartet werden, dass sie etwas erkennen, was Ihren wiederholbaren Tests entgeht.Sie sollten versuchen, alles mit wiederholbaren Tests abzudecken, und die randomisierten Tests als Bonus betrachten.Wenn sie etwas finden, sollte es etwas sein, das Sie nicht vernünftigerweise vorhersagen konnten;ein echter Sonderling.

Wie kann Ihr Mann den Test erneut durchführen, wenn er fehlgeschlagen ist, um festzustellen, ob er das Problem behoben hat?D.h.er verliert die Wiederholbarkeit der Tests.

Obwohl ich denke, dass es wahrscheinlich einen gewissen Nutzen hat, bei Tests eine Menge Zufallsdaten zu verwenden, fällt dies, wie in anderen Antworten erwähnt, eher unter die Überschrift „Auslastungstests“ als alles andere.Es handelt sich sozusagen um eine „Test-by-Hoffnung“-Praxis.Ich denke, dass Ihr Mann in Wirklichkeit einfach nicht darüber nachdenkt, was er zu testen versucht, und dass er diesen Mangel an Nachdenken dadurch ausgleicht, dass er hofft, dass der Zufall irgendwann einen mysteriösen Fehler aufdeckt.

Das Argument, das ich ihm gegenüber vorbringen würde, ist also, dass er faul ist.Oder anders ausgedrückt: Wenn er sich nicht die Zeit nimmt, zu verstehen, was er zu testen versucht, zeigt das wahrscheinlich, dass er den Code, den er schreibt, nicht wirklich versteht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top