Kontext:
Ich arbeite derzeit an einem kleinen Projekt in Python. Normalerweise strukturiere ich meine Klassen mit einigen öffentlichen Methoden, die dokumentiert sind, sich aber hauptsächlich mit den Konzepten auf hoher Ebene (was ein Benutzer der Klasse wissen und verwenden sollte) und einer Reihe versteckter (beginnend mit Unterstrich) Methoden befassen, die für die zuständig sind komplexe oder Low-Level-Verarbeitung.
Ich weiß, dass Tests wichtig sind, um Vertrauen in den Code zu schaffen und um sicherzustellen, dass spätere Änderungen das vorherige Verhalten nicht verletzt haben.
Problem:
Um die übergeordneten öffentlichen Methoden auf einer vertrauenswürdigen Basis aufzubauen, teste ich im Allgemeinen die privaten Methoden. Ich finde es einfacher zu finden, ob und wo eine Codeänderung Regressionen eingeführt hat. Dies bedeutet, dass diese internen Tests bei geringfügigen Änderungen brechen können und repariert / ersetzt werden müssen
Ich weiß aber auch, dass Unit-Testing-Private-Methoden zumindest ein umstrittenes Konzept sind oder häufiger als schlechte Praxis angesehen werden. Der Grund ist: Nur öffentliches Verhalten sollte getestet werden ( Ref. )
Frage:
Ich kümmere mich um die folgenden Best Practices und möchte verstehen:
- Warum ist die Verwendung von Unit-Tests für private / versteckte Methoden schlecht (was ist das Risiko)?
- Was sind die Best Practices, wenn die öffentlichen Methoden eine einfache und / oder komplexe Verarbeitung verwenden können?
Präzision:
- es ist nicht ein , wie man Frage. Python hat kein echtes Konzept der Privatsphäre und versteckte Methoden werden einfach nicht aufgelistet, können aber verwendet werden, wenn Sie ihren Namen kennen
- Ich habe noch nie Programmierregeln und -muster gelernt: Meine letzten Kurse stammen aus den 80ern ... Ich habe hauptsächlich Sprachen durch Ausprobieren und Referenzen im Internet gelernt (Stack Exchange ist seit Jahren mein Favorit).
quelle
Antworten:
Ein paar Gründe:
Wenn Sie versucht sind, die private Methode einer Klasse zu testen, ist dies normalerweise ein Designgeruch (Eisbergklasse, nicht genügend wiederverwendbare öffentliche Komponenten usw.). Es gibt fast immer ein "größeres" Problem.
Sie können sie über die öffentliche Schnittstelle testen (so möchten Sie sie testen, da der Client sie so aufruft / verwendet). Sie können ein falsches Sicherheitsgefühl bekommen, indem Sie grünes Licht für alle bestandenen Tests für Ihre privaten Methoden sehen. Es ist viel besser / sicherer, Edge Cases für Ihre privaten Funktionen über Ihre öffentliche Schnittstelle zu testen.
Sie riskieren schwere Testduplikationen (Tests, die sehr ähnlich aussehen / sich sehr ähnlich anfühlen), indem Sie private Methoden testen. Dies hat erhebliche Konsequenzen, wenn sich die Anforderungen ändern, da viel mehr Tests als erforderlich unterbrochen werden. Es kann Sie auch in eine Position bringen, in der es aufgrund Ihrer Testsuite schwierig ist, eine Umgestaltung vorzunehmen ... was die ultimative Ironie ist, da die Testsuite Ihnen dabei hilft, sicher neu zu gestalten und umzugestalten!
Ein Tipp, wenn Sie immer noch versucht sind, die privaten Teile zu testen (verwenden Sie es nicht, wenn es Sie und YMMV stört, aber es hat in der Vergangenheit für mich gut funktioniert ): Manchmal schreiben Sie Unit-Tests für private Funktionen, nur um sicherzugehen Sie arbeiten genau so, wie Sie denken, dass sie wertvoll sein können (insbesondere, wenn Sie neu in einer Sprache sind). Wenn Sie jedoch sicher sind, dass sie funktionieren, löschen Sie die Tests und stellen Sie immer sicher, dass die öffentlich zugänglichen Tests solide sind und abfangen, wenn jemand eine ungeheure Änderung an dieser privaten Funktion vornimmt.
Wann man private Methoden testet: Da diese Antwort (etwas) populär geworden ist, fühle ich mich verpflichtet zu erwähnen, dass eine "Best Practice" immer genau das ist: eine "Best Practice". Es bedeutet nicht, dass Sie es dogmatisch oder blind tun sollten. Wenn Sie der Meinung sind, dass Sie Ihre privaten Methoden testen sollten und einen legitimen Grund haben (z. B. wenn Sie Charakterisierungstests für eine Legacy-Anwendung schreiben), testen Sie Ihre privaten Methoden . Bestimmte Umstände sind immer wichtiger als allgemeine Regeln oder bewährte Verfahren. Seien Sie sich nur einiger Dinge bewusst, die schief gehen können (siehe oben).
Ich habe eine Antwort, die dies auf SO ausführlich behandelt und die ich hier nicht wiederholen werde: /programming/105007/should-i-test-private-methods-or-only-public-ones/ 47401015 # 47401015
quelle
bin_search(arr, item)
(öffentlich) undbin_search(arr, item, low, hi)
(privat, es gibt viele Möglichkeiten, eine Bin-Suche durchzuführen), alles, was Sie testen müssen, das öffentlich zugängliche ist (bin_search(arr, item)
)Angesichts der Tatsache, dass einer der Hauptzwecke von Komponententests darin besteht, dass Sie die Interna Ihres Programms umgestalten und dann überprüfen können, ob Sie seine Funktionalität nicht beeinträchtigt haben, ist es kontraproduktiv, wenn Ihre Komponententests mit einer so feinen Granularität ausgeführt werden, dass Bei jeder Änderung des Programmcodes müssen Sie Ihre Tests neu schreiben.
quelle
Das Schreiben von Komponententests für private Methoden verknüpft Ihre Komponententests mit Implementierungsdetails.
Unit-Tests sollten das Verhalten einer Klasse an der Außenfläche der Klasse testen (öffentliche API). Unit-Tests sollten nichts über die Innereien einer Klasse wissen müssen. Das Schreiben von Komponententests anhand der Implementierungsdetails einer Klasse bindet Ihnen die Hände, wenn es um die Umgestaltung geht. Refactoring wird diese Tests mit ziemlicher Sicherheit brechen, da sie nicht Teil Ihrer stabilen API sind.
Das heißt, warum möchten Sie vielleicht Unit-Tests für Ihre privaten Methoden schreiben?
Es gibt eine natürliche Spannung zwischen Unit-Tests und inkrementeller Entwicklung. Softwareentwickler, die eine REPL (Read-Eval-Print-Schleife) verwenden, können bestätigen, wie produktiv es sein kann, kleine Funktionen schnell zu schreiben und zu testen, wenn Sie eine Klasse oder Funktion "erweitern". Der einzige gute Weg, dies in Umgebungen zu tun, die auf Unit-Tests basieren, besteht darin, Unit-Tests für private Methoden zu schreiben, aber das ist sehr reibungslos. Das Schreiben von Komponententests benötigt Zeit, Sie benötigen eine tatsächliche Methode zum Testen, und Ihr Testframework muss die Fähigkeit unterstützen, die Methode privat zu halten, damit Ihre externe API nicht verschmutzt wird.
Einige Ökosysteme wie C # und .NET bieten Möglichkeiten zum Erstellen von REPL-ähnlichen Umgebungen (Tools wie Linqpad tun dies), ihre Nützlichkeit ist jedoch eingeschränkt, da Sie keinen Zugriff auf Ihr Projekt haben. Das unmittelbare Fenster in Visual Studio ist unpraktisch. Es verfügt immer noch nicht über volles Intellisense, Sie müssen vollständig qualifizierte Namen verwenden und es löst jedes Mal einen Build aus, wenn Sie es verwenden.
quelle
Aus meiner Erfahrung habe ich herausgefunden, dass Unit-Tests der internen Klassen, Methoden normalerweise bedeuten, dass ich die getesteten Funktionen, Klassen herausnehmen muss. Eine andere Abstraktionsebene erstellen.
Dies führt zu einer besseren Einhaltung des Einzelverantwortungsprinzips.
quelle
Ich denke, dies ist eine gute Frage, da sie ein häufiges Problem beim Testen der Abdeckung aufzeigt. Eine gute Antwort sollte Ihnen jedoch sagen, dass die Frage nicht genau richtig ist, da Sie theoretisch nicht in der Lage sein sollten, private Methoden zu testen . Deshalb sind sie privat .
Vielleicht wäre eine bessere Frage: "Was soll ich tun, wenn ich private Methoden testen möchte?" und die Antwort liegt auf der Hand: Sie sollten sie so belichten, dass Tests möglich sind. Dies bedeutet nicht unbedingt, dass Sie die Methode nur öffentlich machen sollten, und das ist es. Höchstwahrscheinlich möchten Sie eine höhere Abstraktion durchführen. Wechseln Sie zu einer anderen Bibliothek oder API, damit Sie Ihre Tests für diese Bibliothek durchführen können, ohne diese Funktionalität in Ihrer Haupt-API verfügbar zu machen.
Denken Sie daran, dass es einen Grund gibt, warum Ihre Methoden unterschiedliche Zugänglichkeitsstufen haben, und Sie sollten immer darüber nachdenken, wie Ihre Klassen am Ende verwendet werden.
quelle