Manchmal sind private Funktionen eines Moduls oder einer Klasse einfach noch zu extrahierende interne Funktionseinheiten, die möglicherweise ihre eigenen Tests verdienen. Warum also nicht testen? Wir werden später Tests für sie schreiben, wenn sie extrahiert werden. Warum also nicht jetzt die Tests schreiben, wenn sie noch Teil derselben Datei sind?
Demonstrieren:
Zuerst habe ich geschrieben module_a
. Jetzt möchte ich Tests dafür schreiben. Ich möchte die 'private' Funktion testen _private_func
. Ich verstehe nicht, warum ich keinen Test dafür schreiben würde, wenn ich ihn später ohnehin in ein eigenes internes Modul umgestalten und dann Tests dafür schreiben könnte.
Angenommen, ich habe ein Modul mit den folgenden Funktionen (es könnte auch eine Klasse sein):
def public_func(a):
b = _do_stuff(a)
return _do_more_stuff(b)
_do_stuff
und _do_more_stuff
sind "private" Funktionen des Moduls.
Ich verstehe die Idee, dass wir nur die öffentliche Schnittstelle testen sollten, nicht die Implementierungsdetails. Hier ist jedoch die Sache:
_do_stuff
und _do_more_stuff
enthalten den größten Teil der Funktionalität des Moduls. Jeder von ihnen könnte eine öffentliche Funktion eines anderen "internen" Moduls sein. Sie sind jedoch noch nicht weiterentwickelt und groß genug, um in separate Dateien extrahiert zu werden.
Das Testen dieser Funktionen fühlt sich also richtig an, da sie wichtige Funktionseinheiten sind. Wenn sie als öffentliche Funktionen in verschiedenen Modulen wären, hätten wir sie getestet. Warum testen Sie sie nicht, wenn sie noch nicht (oder noch nie) in eine andere Datei extrahiert wurden?
Antworten:
Das Bedürfnis zu testen ist nicht dasselbe wie das Bedürfnis, öffentlich zu sein.
Nicht trivialer Code muss unabhängig von der Exposition getestet werden. Nicht öffentliches Verhalten muss nicht existieren, geschweige denn getestet werden.
Diese widersprüchlichen Ansichten können dazu führen, dass Sie jede Funktion öffentlich machen oder sich weigern möchten, Code in eine Funktion zu zerlegen, es sei denn, er ist öffentlich.
Dies ist nicht die Antwort. Seien Sie bereit, private Hilfsfunktionen zu erstellen. Testen Sie sie über die öffentliche Schnittstelle, die sie so oft wie möglich verwendet.
Wenn das Testen über die öffentliche Schnittstelle die private Funktion nicht ausreichend ausübt, versucht die private Funktion zu viel zuzulassen.
Die Validierung kann dazu beitragen, die Möglichkeiten der privaten Funktion einzugrenzen. Wenn Sie keine Null übergeben können, die die öffentliche Schnittstelle durchläuft, können Sie trotzdem eine Ausnahme auslösen, wenn eine trotzdem durchkommt.
Warum solltest du? Warum testen, was Sie nie sehen werden? Weil sich die Dinge ändern. Es kann jetzt privat sein, aber später öffentlich sein. Der aufrufende Code könnte sich ändern. Code, der null explizit ablehnt, macht die ordnungsgemäße Verwendung und den erwarteten Status deutlich.
Natürlich könnte null in Ordnung sein. Es ist nur ein Beispiel hier. Aber wenn Sie etwas erwarten, ist es nützlich, diese Erwartung klar zu machen.
Dies ist möglicherweise nicht die Art von Test, an die Sie gedacht haben, aber hoffentlich sind Sie bereit, bei Bedarf private Hilfsfunktionen zu erstellen.
Der Wunsch zu testen ist gut, sollte aber nicht die treibende Kraft beim Design Ihrer öffentlichen API sein. Entwerfen Sie die öffentliche API so, dass sie einfach zu verwenden ist. Es wird wahrscheinlich nicht sein, wenn jede Funktion öffentlich ist. Die API sollte etwas sein, das die Benutzer verstehen können, ohne in den Code einzutauchen. Lassen Sie solche Leute nicht fragen, wofür diese seltsame Hilfsfunktion gedacht ist.
Das Ausblenden öffentlicher Hilfsfunktionen in einem internen Modul ist ein Versuch, die Notwendigkeit einer sauberen API zu berücksichtigen und gleichzeitig Helfer zum Testen bereitzustellen. Ich werde nicht sagen, dass das falsch ist. Möglicherweise machen Sie den ersten Schritt in Richtung einer anderen Architekturebene. Aber bitte beherrschen Sie die Kunst, private Hilfsfunktionen durch die öffentlichen Funktionen zu testen, die sie zuerst verwenden. Auf diese Weise werden Sie diese Problemumgehung nicht zu häufig verwenden.
quelle
Kurze Antwort: Nein
Längere Antwort: Ja, aber über die öffentliche 'API' Ihrer Klasse
Die ganze Idee von privaten Mitgliedern einer Klasse ist, dass sie Funktionen darstellen, die außerhalb der 'Codeeinheit' unsichtbar sein sollten, egal wie groß Sie diese Einheit definieren möchten. Im objektorientierten Code wird diese Einheit häufig zu einer Klasse.
Sie sollten Ihre Klasse so gestalten, dass es möglich ist, alle privaten Funktionen über verschiedene Kombinationen von Eingabestatus aufzurufen. Wenn Sie feststellen, dass es keinen relativ einfachen Weg gibt, dies zu tun, deutet dies wahrscheinlich darauf hin, dass Ihr Design genauer betrachtet werden muss.
Nach Klärung der Frage ist dies nur eine Frage der Semantik. Wenn der betreffende Code als separate eigenständige Einheit arbeiten kann und getestet wird, als wäre er öffentlicher Code, kann ich keinen Vorteil darin sehen, ihn nicht in ein eigenständiges Modul zu verschieben. Gegenwärtig dient es nur dazu, zukünftige Entwickler (einschließlich Sie selbst in 6 Monaten) zu verwirren, warum der scheinbar öffentliche Code in einem anderen Modul versteckt ist.
quelle
Der springende Punkt bei privaten Funktionen ist, dass es sich um versteckte Implementierungsdetails handelt, die nach Belieben geändert werden können, ohne die öffentliche API zu ändern. Für Ihren Beispielcode:
Wenn Sie eine Reihe von Tests haben, die nur verwendet werden
public_func
, schreiben Sie sie wie folgt um:Solange das Rückgabeergebnis für einen bestimmten Wert von gleich
a
bleibt, sind alle Ihre Tests gut. Wenn sich das Rückgabeergebnis ändert, schlägt ein Test fehl und zeigt, dass etwas kaputt gegangen ist.Dies ist alles eine gute Sache: statische öffentliche API; gut eingekapseltes Innenleben; und robuste Tests.
Wenn Sie jedoch Tests für
_do_stuff
oder geschrieben_do_more_stuff
und dann die oben genannte Änderung vorgenommen haben, haben Sie jetzt eine Reihe fehlerhafter Tests, nicht weil sich die Funktionalität geändert hat, sondern weil sich die Implementierung dieser Funktionalität geändert hat. Diese Tests müssten neu geschrieben werden, um mit den neuen Funktionen zu arbeiten. Wenn Sie sie jedoch zum Laufen gebracht haben, wissen Sie nur, dass diese Tests mit den neuen Funktionen funktionieren. Sie hätten die ursprünglichen Tests verloren und würden daher nicht wissen, ob sich das Verhalten vonpublic_func
geändert hat, und daher wären Ihre Tests im Grunde genommen nutzlos.Dies ist eine schlechte Sache: eine sich ändernde API; freiliegendes Innenleben eng mit Tests verbunden; und spröde Tests, die sich ändern, sobald Änderungen an der Implementierung vorgenommen werden.
Also nein, testen Sie keine privaten Funktionen. Je.
quelle