Ich habe mich wirklich in Unit-Tests und TDD verliebt - ich bin testinfiziert.
Unit-Tests werden jedoch normalerweise für öffentliche Methoden verwendet. Manchmal muss ich allerdings einige Annahmen-Behauptungen auch in privaten Methoden testen, da einige von ihnen "gefährlich" sind und Refactoring nicht weiterhelfen kann. (Ich weiß, dass das Testen von Frameworks das Testen privater Methoden ermöglicht.)
So wurde es zu meiner Gewohnheit, dass sowohl die erste als auch die letzte Zeile einer privaten Methode Behauptungen sind.
Mir ist jedoch aufgefallen, dass ich Behauptungen eher in öffentlichen Methoden (als auch im privaten) verwende, nur "um sicherzugehen". Könnte dies "Testen von Duplikaten" sein, da die Annahmen der öffentlichen Methode von außen durch das Unit-Testing-Framework getestet werden?
Könnte sich jemand zu viele Behauptungen als Codegeruch vorstellen?
quelle
Antworten:
Diese Behauptungen sind sehr nützlich, um Ihre Annahmen zu testen, aber sie dienen auch einem anderen wirklich wichtigen Zweck: der Dokumentation. Jeder Leser einer öffentlichen Methode kann die Asserts lesen, um die Vor- und Nachbedingungen schnell zu ermitteln, ohne sich die Testsuite ansehen zu müssen. Aus diesem Grund empfehle ich, diese Zusicherungen aus Dokumentationsgründen und nicht aus Testgründen aufzubewahren. Technisch gesehen duplizieren Sie die Behauptungen, aber sie dienen zwei unterschiedlichen Zwecken und sind in beiden Fällen sehr nützlich.
Es ist besser, sie als Zusicherungen beizubehalten, als nur Kommentare zu verwenden, da sie die Annahmen bei jeder Ausführung aktiv überprüfen.
quelle
Es hört sich so an, als würden Sie versuchen, Design-by-Contract von Hand zu erstellen .
DbC ist eine gute Idee, aber Sie sollten zumindest in Betracht ziehen, zu einer Sprache zu wechseln, die es von Haus aus unterstützt (wie Eiffel ), oder zumindest ein Vertragsframework für Ihre Plattform verwenden (z. B. Microsoft Code Contracts für .NET)ist ziemlich nett, der wohl ausgefeilteste Vertragsrahmen überhaupt, sogar mächtiger als Eiffel. Auf diese Weise können Sie die Leistungsfähigkeit von Verträgen besser nutzen. Sie können z. B. mit einem vorhandenen Framework die Verträge in Ihrer Dokumentation oder einer IDE anzeigen (z. B. werden Codeverträge für .NET in IntelliSense angezeigt und können, wenn Sie VS Ultimate haben, während der Kompilierung sogar von einem automatischen Theorembeweiser statisch überprüft werden Sie tippen, und viele Java-Vertrags-Frameworks haben JavaDoc-Doclets, die die Verträge automatisch in Ihre JavaDoc-API-Dokumentation extrahieren.
Und selbst wenn sich herausstellt, dass es in Ihrer Situation keine Alternative zu einer manuellen Ausführung gibt, wissen Sie jetzt zumindest, wie es heißt, und können sich darüber informieren.
Also, kurz gesagt: Wenn Sie tatsächlich DbC machen, auch wenn Sie es nicht wissen, dann sind diese Behauptungen vollkommen in Ordnung.
quelle
Wann immer Sie nicht die volle Kontrolle über Ihre Eingabeparameter haben, ist es eine sehr gute Idee, vorab auf einfache Fehler zu testen. Zum Beispiel auf null fehlschlagen.
Dies ist nicht Vervielfältigung Ihrer Tests, da sie , dass der Code versagt angemessen testen sollte gegeben schlecht Eingabeparameter und dann dokumentieren , dass .
Ich denke nicht, dass Sie auf den Rückgabeparametern behaupten sollten (es sei denn, Sie haben explizit eine Invariante, die der Leser verstehen soll). Dies ist auch die Aufgabe der Unittests.
Persönlich mag ich die
assert
Aussage in Java nicht, da sie abgeschaltet werden kann und es sich dann um eine falsche Sicherheit handelt.quelle
Ich denke, dass die Verwendung von Behauptungen in öffentlichen Methoden noch wichtiger ist, da Sie dort die Eingaben nicht kontrollieren und wahrscheinlich eine fehlerhafte Annahme haben.
Das Testen der Eingabebedingungen sollte mit allen öffentlichen und geschützten Methoden erfolgen. Wenn die Eingaben direkt an eine private Methode übergeben werden, ist das Testen der Eingaben möglicherweise redundant.
Das Testen von Ausgabebedingungen (z. B. Objektstatus oder Rückgabewert! = Null) sollte in den inneren Methoden (z. B. privaten Methoden) erfolgen. Wenn die Ausgaben ohne zusätzliche Berechnungen oder Änderungen des inneren Zustands direkt von einer privaten Methode an die Ausgabe einer öffentlichen Methode übergeben werden, ist das Testen der Ausgabebedingungen der öffentlichen Methode möglicherweise redundant.
Ich stimme jedoch Oleksi zu, dass die Redundanz die Lesbarkeit und die Wartbarkeit erhöhen kann (wenn die direkte Zuweisung oder Rückgabe in Zukunft nicht mehr der Fall ist).
quelle
Es ist schwierig, sprachunabhängig in Bezug auf dieses Problem zu sein, da die Details der Implementierung von Behauptungen und der ordnungsgemäßen Fehler- / Ausnahmebehandlung einen Einfluss auf die Antwort haben. Hier sind meine 0,02 US-Dollar, basierend auf meinen Kenntnissen in Java und C ++.
Behauptungen in privaten Methoden sind eine gute Sache, vorausgesetzt, Sie gehen nicht über Bord und platzieren sie überall . Wenn Sie sie mit wirklich einfachen Methoden anwenden oder wiederholt Dinge wie unveränderliche Felder überprüfen, ist der Code unnötig überfüllt.
Behauptungen in öffentlichen Methoden werden im Allgemeinen am besten vermieden. Sie sollten weiterhin überprüfen, ob der Methodenvertrag nicht verletzt wurde. Wenn dies jedoch der Fall ist, sollten Sie entsprechend typisierte Ausnahmebedingungen mit aussagekräftigen Nachrichten auslösen, den Status nach Möglichkeit wiederherstellen usw. (was @rwong als "vollständig" bezeichnet) ordnungsgemäße Fehlerbehandlung ").
Im Allgemeinen sollten Sie Behauptungen nur verwenden, um Ihre Entwicklung / Ihr Debugging zu unterstützen. Sie können nicht davon ausgehen, dass jeder, der Ihre API verwendet, sogar Zusicherungen aktiviert hat, wenn er Ihren Code verwendet. Obwohl sie bei der Dokumentation des Codes hilfreich sind, gibt es oft bessere Möglichkeiten, um dieselben Dinge zu dokumentieren (z. B. Methodendokumentation, Ausnahmen).
quelle
Ein weiterer Grund für viele Behauptungen und Duplikationen ist, dass Sie nicht wissen, wie, wann oder von wem die Klasse im Laufe ihrer Lebensdauer geändert wird. Wenn Sie Code zum Wegwerfen schreiben, der in einem Jahr tot sein wird, ist dies kein Problem. Wenn Sie Code schreiben, der in mehr als 20 Jahren verwendet wird, sieht er ganz anders aus - und eine Annahme, die Sie getroffen haben, ist möglicherweise nicht mehr gültig. Der Typ, der diese Änderung vornimmt, wird Ihnen für die Behauptungen danken.
Auch sind nicht alle Programmierer perfekt - auch hier bedeuten die Behauptungen, dass sich einer dieser "Ausrutscher" nicht zu weit ausbreitet.
Unterschätzen Sie nicht die Auswirkung dieser Behauptungen (und anderer Überprüfungen von Annahmen) auf die Reduzierung der Wartungskosten.
quelle
Doppelte Zusicherungen sind per se nicht falsch, aber die Zusicherungen "nur um sicherzustellen" sind nicht die besten. Es läuft wirklich darauf hinaus, was genau jeder Test zu erreichen versucht. Nur behaupten, was unbedingt benötigt wird. Wenn ein Test mithilfe von Moq überprüft, ob eine Methode aufgerufen wurde, spielt es keine Rolle, was nach dem Aufrufen dieser Methode geschieht. Der Test muss lediglich sicherstellen, dass die Methode aufgerufen wurde.
Wenn jeder einzelne Komponententest mit Ausnahme von einem oder zwei denselben Satz von Zusicherungen enthält, können alle Tests, wenn Sie ein wenig umgestalten, aus genau demselben Grund fehlschlagen, anstatt Ihnen die tatsächlichen Auswirkungen des Umgestalters zu zeigen. Sie könnten in eine Situation geraten, in der Sie alle Tests ausführen, die alle fehlschlagen, weil jeder Test die gleichen Aussagen enthält. Sie beheben diesen Fehler, führen die Tests erneut aus, sie schlagen aus einem anderen Grund fehl, und Sie beheben diesen Fehler. Wiederholen, bis fertig.
Berücksichtigen Sie auch die Wartung Ihres Testprojekts. Was passiert, wenn Sie einen neuen Parameter hinzufügen oder die Ausgabe geringfügig optimieren? Müssen Sie eine Reihe von Tests wiederholen und eine Zusicherung ändern oder eine Zusicherung hinzufügen? Abhängig von Ihrem Code müssen Sie möglicherweise viel mehr Einstellungen vornehmen, um sicherzustellen, dass alle Asserts erfolgreich sind.
Ich kann den Reiz verstehen, doppelte Aussagen in den Komponententest einbeziehen zu wollen, aber es ist wirklich übertrieben. Bei meinem ersten Testprojekt bin ich den gleichen Weg gegangen. Ich bin davon weggegangen, weil mich die Wartung allein verrückt gemacht hat.
quelle
Wenn Ihr Test-Framework Zugriffsmethoden zulässt, ist das Testen privater Methoden in Units ebenfalls eine gute Idee (IMO).
Ich mache. Behauptungen sind in Ordnung, aber Ihr erstes Ziel sollte es sein, dass das Szenario nicht einmal möglich ist . nicht nur, dass es nicht passiert.
quelle
Es ist eine schlechte Übung.
Sie sollten keine öffentlichen / privaten Methoden testen. Sie sollten die Klasse als Ganzes testen. Stellen Sie einfach sicher, dass Sie eine gute Abdeckung haben.
Wenn Sie die (primitive) Methode als Faustregel verwenden, um jede Methode einzeln zu testen, fällt es Ihnen extrem schwer, Ihre Klasse in Zukunft neu zu faktorisieren. Und das ist eines der besten Dinge, die TDD Ihnen ermöglicht.
Außerdem ist es eine Vervielfältigung. Darüber hinaus deutet dies darauf hin, dass der Verfasser des Codes nicht wirklich wusste, was er tat. Und das Lustige ist, dass du es tust .
Einige Leute behandeln ihre Tests mit weniger Sorgfalt als ihren Produktionscode. Sie sollten nicht. Meiner Erfahrung nach ist es sogar ratsam, die Tests mit größerer Sorgfalt zu behandeln. Sie sind es wert.
quelle