Sowohl Asserts als auch Unit-Tests dienen als Dokumentation für eine Codebasis und als Mittel zum Auffinden von Fehlern. Die Hauptunterschiede bestehen darin, dass Asserts als Plausibilitätsprüfungen fungieren und reale Eingaben erkennen, wohingegen Komponententests für bestimmte simulierte Eingaben ausgeführt werden und Tests mit einer einzigen genau definierten "richtigen Antwort" sind. Was sind die relativen Vorteile der Verwendung von Asserts im Vergleich zu Unit-Tests als Hauptmittel zur Überprüfung der Richtigkeit? Welches sollte Ihrer Meinung nach stärker betont werden?
testing
unit-testing
assertions
dsimcha
quelle
quelle
:-)
Antworten:
Asserts sind nützlich, um Sie über den internen Status des Programms zu informieren . Zum Beispiel, dass Ihre Datenstrukturen einen gültigen Status haben, zum Beispiel, dass eine
Time
Datenstruktur nicht den Wert von enthält25:61:61
. Die von Asserts überprüften Bedingungen sind:Voraussetzungen, die sicherstellen, dass der Anrufer seinen Vertrag einhält,
Nachbedingungen, die sicherstellen, dass der Angerufene seinen Vertrag einhält, und
Invarianten, die sicherstellen, dass die Datenstruktur nach der Rückkehr der Funktion immer eine Eigenschaft enthält. Eine Invariante ist eine Bedingung, die eine Vorbedingung und eine Nachbedingung ist.
Unit-Tests sind nützlich, um Sie über das externe Verhalten des Moduls zu informieren . Sie
Stack
kann einen konsistenten Zustand, nachdem diepush()
Methode aufgerufen wird, aber wenn die Größe des Stapels nicht durch drei nicht erhöht , nachdem es dreimal aufgerufen wird, dann ist das ein Fehler ist. (Zum Beispiel der triviale Fall, dass die falschepush()
Implementierung nur die Asserts und Exits überprüft.)Genau genommen besteht der Hauptunterschied zwischen Zusicherungen und Komponententests darin, dass Komponententests Testdaten enthalten (Werte, mit denen das Programm ausgeführt werden kann), während Zusicherungen dies nicht tun. Das heißt, Sie können Ihre Komponententests automatisch ausführen, während Sie dies für Behauptungen nicht sagen können. Für diese Diskussion habe ich angenommen, dass Sie über das Ausführen des Programms im Kontext von Funktionstests höherer Ordnung sprechen (die das gesamte Programm ausführen und keine Module wie Unit-Tests ansteuern). Wenn Sie nicht über automatisierte Funktionstests als Mittel sprechen, um "echte Eingaben zu sehen", dann liegt der Wert eindeutig in der Automatisierung, und somit würden die Komponententests gewinnen. Wenn Sie im Rahmen von (automatisierten) Funktionstests darüber sprechen, siehe unten.
Es kann zu Überschneidungen bei den getesteten Objekten kommen. Beispielsweise kann
Stack
die Nachbedingung von tatsächlich behaupten, dass sich die Stapelgröße um eins erhöht. Was in dieser Behauptung ausgeführt werden kann, ist jedoch begrenzt: Soll auch überprüft werden, ob das oberste Element das ist, was gerade hinzugefügt wurde?Ziel ist es für beide, die Qualität zu steigern. Bei Unit-Tests geht es darum, Fehler zu finden. Bei Assertions besteht das Ziel darin, das Debuggen zu vereinfachen, indem ungültige Programmzustände sofort nach ihrem Auftreten beobachtet werden.
Beachten Sie, dass keine der Techniken die Richtigkeit überprüft. In der Tat, wenn Sie Unit-Tests durchführen, um sicherzustellen, dass das Programm korrekt ist, werden Sie wahrscheinlich einen uninteressanten Test finden, von dem Sie wissen, dass er funktionieren wird. Es ist ein psychologischer Effekt: Sie werden alles tun, um Ihr Ziel zu erreichen. Wenn es Ihr Ziel ist, Fehler zu finden, werden Ihre Aktivitäten dies widerspiegeln.
Beide sind wichtig und haben ihre eigenen Zwecke.
[Als letzte Anmerkung zu Behauptungen: Um den größtmöglichen Nutzen zu erzielen, müssen Sie sie an allen kritischen Punkten in Ihrem Programm verwenden und nicht an einigen Schlüsselfunktionen. Andernfalls ist die ursprüngliche Ursache des Problems möglicherweise maskiert und ohne stundenlanges Debuggen schwer zu erkennen.]
quelle
Denken Sie bei der Beschreibung von Behauptungen daran, dass diese mit einem Tastendruck ausgeschaltet werden können.
Beispiel einer sehr schlechten Behauptung:
Warum ist das so schlimm? Weil keine Fehlerprüfung durchgeführt wird, wenn diese Zusicherung aufgrund der Definition von NDEBUG übersprungen wird.
Ein Unit-Test würde (wahrscheinlich) nur am obigen Code scheitern. Sicher, es hat seine Arbeit getan, indem es Ihnen sagte, dass etwas schief gelaufen ist, oder? Wie wahrscheinlich ist es
malloc()
, dass der Test fehlschlägt?Behauptungen dienen zu Debugging-Zwecken, wenn ein Programmierer implizieren muss, dass kein "normales" Ereignis die Behauptung auslösen würde.
malloc()
ein Scheitern ist in der Tat ein normales Ereignis und sollte daher niemals behauptet werden.Es gibt viele andere Fälle, in denen Behauptungen verwendet werden, anstatt mit Dingen, die schief gehen könnten, angemessen umzugehen. Dies ist der Grund, warum Behauptungen einen schlechten Ruf erhalten und warum Sprachen wie Go sie nicht enthalten.
Unit-Tests sollen Ihnen mitteilen, wann etwas, das Sie geändert haben, etwas anderes kaputt gemacht hat. Sie wurden entwickelt, um Sie (in den meisten Fällen) davon abzuhalten, jedes Mal, wenn Sie ein Build erstellen, alle Funktionen des Programms zu durchlaufen (Tester sind jedoch für Releases wichtig).
Es gibt wirklich keine eindeutige Korrelation zwischen den beiden, außer dass beide Ihnen mitteilen, dass etwas schief gelaufen ist. Stellen Sie sich eine Zusicherung als Haltepunkt in etwas vor, an dem Sie gerade arbeiten, ohne einen Debugger verwenden zu müssen. Stellen Sie sich einen Komponententest vor, der Ihnen sagt, ob Sie etwas kaputt gemacht haben, an dem Sie nicht arbeiten.
quelle
Beide Tools tragen zur Verbesserung der Gesamtqualität des von Ihnen erstellten Systems bei. Viel hängt davon ab, welche Sprache Sie verwenden, welche Art von Anwendung Sie erstellen und wo Sie Ihre Zeit am besten verbringen. Ganz zu schweigen davon, dass Sie ein paar Denkanstöße haben.
Wenn Sie eine Sprache ohne
assert
Schlüsselwort verwenden, können Sie zunächst keine Zusicherungen verwenden (zumindest nicht so, wie wir hier sprechen). Java hatte lange Zeit keinassert
Schlüsselwort und einige Sprachen immer noch nicht. Unit Testing wird dann um einiges wichtiger. In einigen Sprachen werden die Assertions nur ausgeführt, wenn ein Flag gesetzt ist (hier wiederum mit Java). Wenn der Schutz nicht immer vorhanden ist, ist dies keine sehr nützliche Funktion.Es gibt eine Denkschule, die besagt, dass Sie, wenn Sie etwas "behaupten", genauso gut einen
if
/throw
bedeutungsvollen Ausnahmeblock schreiben könnten . Dieser Denkprozess kommt von vielen Aussagen, die am Anfang einer Methode stehen, um sicherzustellen, dass alle Werte in Grenzen sind. Das Testen Ihrer Vorbedingungen ist ein sehr wichtiger Teil einer erwarteten Nachbedingung.Unit-Tests sind zusätzlicher Code, der geschrieben und gepflegt werden muss. Für viele ist dies ein Nachteil. Mit der aktuellen Anzahl von Unit-Test-Frameworks können Sie jedoch eine größere Anzahl von Testbedingungen mit vergleichsweise wenig Code generieren. Parametrisierte Tests und "Theorien" führen denselben Test mit einer großen Anzahl von Datenproben durch, die einige schwer auffindbare Fehler aufdecken können.
Ich persönlich habe festgestellt, dass ich mit Unit-Tests mehr Laufleistung erhalte als mit Sprinkling-Tests. Dies liegt jedoch an den Plattformen, auf denen ich die meiste Zeit arbeite (Java / C #). Andere Sprachen bieten eine zuverlässigere Unterstützung für Assertions und sogar "Design by Contract" (siehe unten), um noch mehr Garantien zu bieten. Wenn ich mit einer dieser Sprachen arbeite, verwende ich möglicherweise mehr DBC als Unit-Tests.
http://en.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support
quelle