Ich habe diesen Beitrag über das Testen privater Methoden gelesen . Normalerweise teste ich sie nicht, weil ich immer dachte, es sei schneller, nur öffentliche Methoden zu testen, die von außerhalb des Objekts aufgerufen werden. Testen Sie private Methoden? Soll ich sie immer testen?
unit-testing
testing
language-agnostic
Patrick Desjardins
quelle
quelle
Antworten:
Ich teste keine privaten Methoden. Eine private Methode ist ein Implementierungsdetail, das den Benutzern der Klasse verborgen bleiben sollte. Durch das Testen privater Methoden wird die Kapselung unterbrochen.
Wenn ich feststelle, dass die private Methode riesig oder komplex oder wichtig genug ist, um eigene Tests zu erfordern, stelle ich sie einfach in eine andere Klasse und mache sie dort öffentlich ( Methodenobjekt ). Dann kann ich leicht die zuvor private, aber jetzt öffentliche Methode testen, die jetzt in einer eigenen Klasse lebt.
quelle
Was ist der Zweck des Testens?
Die Mehrheit der bisherigen Antworten besagt, dass private Methoden Implementierungsdetails sind, die keine Rolle spielen (oder zumindest nicht spielen sollten), solange die öffentliche Schnittstelle gut getestet ist und funktioniert. Das ist absolut richtig, wenn Sie nur testen möchten, ob die öffentliche Schnittstelle funktioniert .
Persönlich besteht meine Hauptanwendung für Codetests darin, sicherzustellen, dass zukünftige Codeänderungen keine Probleme verursachen, und meine Debugging-Bemühungen zu unterstützen, wenn dies der Fall ist. Ich finde, dass das Testen der privaten Methoden genauso gründlich ist wie die öffentliche Schnittstelle (wenn nicht mehr!) Diesen Zweck unterstützt.
Bedenken Sie: Sie haben die öffentliche Methode A, die die private Methode B aufruft. A und B verwenden beide die Methode C. C wird geändert (möglicherweise von Ihnen, möglicherweise von einem Anbieter), wodurch A beginnt, seine Tests nicht zu bestehen. Wäre es nicht nützlich, auch Tests für B durchzuführen, obwohl diese privat sind, damit Sie wissen, ob das Problem in der Verwendung von C durch A, der Verwendung von C durch B oder beidem liegt?
Das Testen privater Methoden bietet auch dann einen Mehrwert, wenn die Testabdeckung der öffentlichen Schnittstelle unvollständig ist. Während dies eine Situation ist, die wir im Allgemeinen vermeiden möchten, hängt das Testen der Effizienzeinheiten sowohl von den Tests ab, bei denen Fehler festgestellt werden, als auch von den damit verbundenen Entwicklungs- und Wartungskosten dieser Tests. In einigen Fällen können die Vorteile einer 100% igen Testabdeckung als unzureichend beurteilt werden, um die Kosten dieser Tests zu rechtfertigen, was zu Lücken in der Testabdeckung der öffentlichen Schnittstelle führt. In solchen Fällen kann ein gezielter Test einer privaten Methode eine sehr effektive Ergänzung der Codebasis sein.
quelle
testDoSomething()
testDoSomethingPrivate()
wenn Sie nur die öffentlichen Methoden testen und der Test fehlschlägt. Es könnte entweder oder sein . Dies macht den Test weniger wertvoll. . Hier sind weitere Gründe für das Testen von Private Stackoverflow.com/questions/34571/… :Ich neige dazu, den Ratschlägen von Dave Thomas und Andy Hunt in ihrem Buch Pragmatic Unit Testing zu folgen :
Aber manchmal kann ich mich nicht davon abhalten, private Methoden zu testen, weil es mir das Gefühl gibt, ein völlig robustes Programm zu erstellen.
quelle
Ich fühle mich gezwungen, private Funktionen zu testen, da ich immer mehr einer unserer neuesten QS-Empfehlungen in unserem Projekt folge:
Der Nebeneffekt der Durchsetzung dieser Richtlinie besteht nun darin, dass viele meiner sehr großen öffentlichen Funktionen in viel fokussiertere, besser benannte private Funktionen unterteilt werden.
Die öffentliche Funktion ist (natürlich) immer noch vorhanden, wird jedoch im Wesentlichen darauf reduziert, alle diese privaten "Unterfunktionen" zu nennen.
Das ist eigentlich cool, weil der Callstack jetzt viel einfacher zu lesen ist (anstelle eines Fehlers innerhalb einer großen Funktion habe ich einen Fehler in einer Unter-Unterfunktion mit dem Namen der vorherigen Funktionen im Callstack, um mir das Verständnis zu erleichtern 'wie ich dorthin gekommen bin')
Es scheint jedoch jetzt einfacher zu sein, diese privaten Funktionen direkt zu testen und das Testen der großen öffentlichen Funktion einer Art Integrationstest zu überlassen, bei dem ein Szenario angegangen werden muss.
Nur meine 2 Cent.
quelle
Ja, ich teste private Funktionen, denn obwohl sie mit Ihren öffentlichen Methoden getestet werden, ist es in TDD (Test Driven Design) hilfreich, den kleinsten Teil der Anwendung zu testen. Auf private Funktionen kann jedoch nicht zugegriffen werden, wenn Sie sich in Ihrer Testeinheitsklasse befinden. Hier ist, was wir tun, um unsere privaten Methoden zu testen.
Warum haben wir private Methoden?
Private Funktionen existieren hauptsächlich in unserer Klasse, weil wir lesbaren Code in unseren öffentlichen Methoden erstellen möchten. Wir möchten nicht, dass der Benutzer dieser Klasse diese Methoden direkt aufruft, sondern über unsere öffentlichen Methoden. Außerdem möchten wir ihr Verhalten beim Erweitern der Klasse nicht ändern (im Fall von geschützt), daher ist es eine private.
Beim Codieren verwenden wir Test-Driven-Design (TDD). Dies bedeutet, dass wir manchmal auf eine Funktionalität stoßen, die privat ist und getestet werden soll. Private Funktionen können in phpUnit nicht getestet werden, da wir in der Testklasse nicht auf sie zugreifen können (sie sind privat).
Wir denken hier sind 3 Lösungen:
1. Sie können Ihre Privaten mit Ihren öffentlichen Methoden testen
Vorteile
Nachteile
2. Wenn das Private so wichtig ist, ist es vielleicht ein Code-Geruch, eine neue separate Klasse dafür zu erstellen
Vorteile
Nachteile
3. Ändern Sie den Zugriffsmodifikator in (final) protected
Vorteile
Nachteile
Beispiel
Unsere Testeinheit kann jetzt test_sleepWithSuspect aufrufen, um unsere frühere private Funktion zu testen.
quelle
Ich mag es aus mehreren Gründen nicht, private Funktionen zu testen. Sie sind wie folgt (dies sind die Hauptpunkte für die TLDR-Leute):
Ich werde jedes davon mit einem konkreten Beispiel erklären. Es stellt sich heraus, dass 2) und 3) etwas eng miteinander verbunden sind, so dass ihr Beispiel ähnlich ist, obwohl ich sie als separate Gründe betrachte, warum Sie private Methoden nicht testen sollten.
Es ist manchmal angebracht, private Methoden zu testen. Es ist nur wichtig, sich der oben aufgeführten Nachteile bewusst zu sein. Ich werde später genauer darauf eingehen.
Ich gehe auch darauf ein, warum TDD am Ende keine gültige Entschuldigung für das Testen privater Methoden ist.
Umgestaltung Ihres Weges aus einem schlechten Design
Eines der häufigsten (Anti) Muster, das ich sehe, ist das, was Michael Feathers eine "Eisberg" -Klasse nennt (wenn Sie nicht wissen, wer Michael Feathers ist, kaufen / lesen Sie sein Buch "Effektiv mit Legacy-Code arbeiten" eine wissenswerte Person, wenn Sie ein professioneller Softwareentwickler / -entwickler sind). Es gibt andere (Anti) Muster, die dazu führen, dass dieses Problem auftritt, aber dies ist bei weitem das häufigste, über das ich gestolpert bin. "Iceberg" -Klassen haben eine öffentliche Methode, und der Rest ist privat (weshalb es verlockend ist, die privaten Methoden zu testen). Es wird als "Eisberg" -Klasse bezeichnet, da normalerweise eine einzelne öffentliche Methode auftaucht, der Rest der Funktionalität jedoch in Form privater Methoden unter Wasser verborgen ist.
Beispielsweise möchten Sie möglicherweise testen,
GetNextToken()
indem Sie eine Zeichenfolge nacheinander aufrufen und feststellen, dass das erwartete Ergebnis zurückgegeben wird. Eine solche Funktion erfordert einen Test: Dieses Verhalten ist nicht trivial, insbesondere wenn Ihre Tokenisierungsregeln komplex sind. Stellen wir uns vor, es sei nicht allzu komplex, und wir wollen nur Token einbinden, die durch den Raum begrenzt sind. Sie schreiben also einen Test, vielleicht sieht er ungefähr so aus (ein sprachunabhängiger Pseudocode, hoffentlich ist die Idee klar):Nun, das sieht eigentlich ganz gut aus. Wir möchten sicherstellen, dass wir dieses Verhalten beibehalten, wenn wir Änderungen vornehmen. Ist
GetNextToken()
aber eine private Funktion! Daher können wir es nicht so testen, da es nicht einmal kompiliert wird (vorausgesetzt, wir verwenden eine Sprache, die im Gegensatz zu einigen Skriptsprachen wie Python tatsächlich öffentlich / privat erzwingt). Aber wie wäre es, dieRuleEvaluator
Klasse so zu ändern , dass sie dem Prinzip der Einzelverantwortung (Prinzip der Einzelverantwortung) folgt? Zum Beispiel scheinen Parser, Tokenizer und Evaluator in einer Klasse zusammengefasst zu sein. Wäre es nicht besser, diese Verantwortlichkeiten einfach zu trennen? Wenn Sie eineTokenizer
Klasse erstellen , sind die öffentlichen Methoden außerdemHasMoreTokens()
undGetNextTokens()
. DieRuleEvaluator
Klasse könnte eine habenTokenizer
Objekt als Mitglied. Jetzt können wir den gleichen Test wie oben beibehalten, außer dass wir dieTokenizer
Klasse anstelle derRuleEvaluator
Klasse testen .So könnte es in UML aussehen:
Beachten Sie, dass dieses neue Design die Modularität erhöht, sodass Sie diese Klassen möglicherweise in anderen Teilen Ihres Systems wiederverwenden können (bevor Sie dies nicht konnten, können private Methoden per Definition nicht wiederverwendet werden). Dies ist der Hauptvorteil des Ausfalls des RuleEvaluator zusammen mit einer besseren Verständlichkeit / Lokalität.
Der Test würde sehr ähnlich aussehen, außer dass er diesmal tatsächlich kompiliert würde, da die
GetNextToken()
Methode jetzt für dieTokenizer
Klasse öffentlich ist :Testen privater Komponenten über eine öffentliche Schnittstelle und Vermeiden von Testduplikationen
Selbst wenn Sie nicht glauben, dass Sie Ihr Problem in weniger modulare Komponenten aufteilen können (was Sie in 95% der Fälle tun können, wenn Sie es nur versuchen ), können Sie die privaten Funktionen einfach über eine öffentliche Schnittstelle testen. Oft sind private Mitglieder keinen Test wert, da sie über die öffentliche Schnittstelle getestet werden. Oft sehe ich Tests, die aussehen sehr gut ähnlich , aber zwei verschiedene Funktionen / Methoden testen. Was am Ende passiert, ist, dass Sie, wenn sich die Anforderungen ändern (und dies immer tun), jetzt 2 fehlerhafte Tests anstelle von 1 haben. Und wenn Sie wirklich alle Ihre privaten Methoden getestet haben, haben Sie möglicherweise eher 10 fehlerhafte Tests anstelle von 1. Kurz gesagt Testen privater Funktionen (mithilfe von
FRIEND_TEST
oder sie öffentlich zu machen oder Reflexion zu verwenden), die andernfalls über eine öffentliche Schnittstelle getestet werden könnten, kann zu Testduplikationen führen und / oder Reflexion verwenden, werden Sie es auf lange Sicht normalerweise bereuen.. Sie wollen das wirklich nicht, denn nichts tut mehr weh als Ihre Testsuite, die Sie verlangsamt. Es soll die Entwicklungszeit verkürzen und die Wartungskosten senken! Wenn Sie private Methoden testen, die ansonsten über eine öffentliche Schnittstelle getestet werden, kann die Testsuite genau das Gegenteil bewirken und die Wartungskosten und die Entwicklungszeit aktiv erhöhen. Wenn Sie eine private Funktion öffentlich machen oder wenn Sie so etwas verwendenFRIEND_TEST
Betrachten Sie die folgende mögliche Implementierung der
Tokenizer
Klasse:Angenommen, dies
SplitUpByDelimiter()
ist für die Rückgabe eines Arrays verantwortlich, sodass jedes Element im Array ein Token ist. Sagen wir einfach, dasGetNextToken()
ist einfach ein Iterator über diesen Vektor. Ihr öffentlicher Test könnte also so aussehen:Stellen wir uns vor, wir hätten das, was Michael Feather als tastendes Werkzeug bezeichnet . Mit diesem Tool können Sie die privaten Bereiche anderer Personen berühren. Ein Beispiel ist
FRIEND_TEST
von googletest oder Reflexion, wenn die Sprache es unterstützt.Nehmen wir jetzt an, die Anforderungen ändern sich und die Tokenisierung wird viel komplexer. Sie entscheiden, dass ein einfaches Zeichenfolgenbegrenzer nicht ausreicht, und Sie benötigen ein
Delimiter
Klasse, um den Job zu erledigen. Natürlich erwarten Sie, dass ein Test abbricht, aber dieser Schmerz nimmt zu, wenn Sie private Funktionen testen.Wann können private Methoden getestet werden?
In der Software gibt es keine "Einheitsgröße". Manchmal ist es in Ordnung (und eigentlich ideal), "die Regeln zu brechen". Ich empfehle nachdrücklich, private Funktionen nicht zu testen, wenn Sie können. Es gibt zwei Hauptsituationen, in denen ich denke, dass es in Ordnung ist:
Ich habe ausgiebig mit Legacy-Systemen gearbeitet (weshalb ich so ein großer Michael Feathers-Fan bin), und ich kann mit Sicherheit sagen, dass es manchmal einfach am sichersten ist, nur die private Funktionalität zu testen. Dies kann besonders hilfreich sein, um "Charakterisierungstests" in die Grundlinie aufzunehmen.
Sie sind in Eile und müssen das Schnellste tun, was hier und jetzt möglich ist. Auf lange Sicht möchten Sie keine privaten Methoden testen. Aber ich werde sagen, dass es normalerweise einige Zeit dauert, um Designprobleme zu beheben. Und manchmal muss man in einer Woche versenden. Das ist in Ordnung: Machen Sie es schnell und schmutzig und testen Sie die privaten Methoden mit einem tastenden Werkzeug, wenn dies Ihrer Meinung nach der schnellste und zuverlässigste Weg ist, um die Arbeit zu erledigen. Aber verstehen Sie, dass das, was Sie getan haben, auf lange Sicht nicht optimal war, und denken Sie darüber nach, darauf zurückzukommen (oder, wenn es vergessen wurde, aber Sie es später sehen, beheben Sie es).
Es gibt wahrscheinlich andere Situationen, in denen es in Ordnung ist. Wenn Sie denken, dass es in Ordnung ist und Sie eine gute Rechtfertigung haben, dann tun Sie es. Niemand hält dich auf. Seien Sie sich nur der möglichen Kosten bewusst.
Die TDD-Entschuldigung
Abgesehen davon mag ich es wirklich nicht, wenn Leute TDD als Ausrede für das Testen privater Methoden verwenden. Ich übe TDD und ich glaube nicht, dass TDD Sie dazu zwingt. Sie können zuerst Ihren Test (für Ihre öffentliche Schnittstelle) schreiben und dann Code schreiben, um diese Schnittstelle zu erfüllen. Manchmal schreibe ich einen Test für eine öffentliche Schnittstelle und erfülle ihn, indem ich auch eine oder zwei kleinere private Methoden schreibe (aber ich teste die privaten Methoden nicht direkt, aber ich weiß, dass sie funktionieren oder mein öffentlicher Test fehlschlagen würde ). Wenn ich Randfälle dieser privaten Methode testen muss, schreibe ich eine ganze Reihe von Tests, die sie über meine öffentliche Schnittstelle treffen.Wenn Sie nicht herausfinden können, wie Sie die Randfälle treffen können, ist dies ein starkes Zeichen dafür, dass Sie kleine Komponenten mit jeweils eigenen öffentlichen Methoden umgestalten müssen. Es ist ein Zeichen dafür, dass Ihre privaten Funktionen zu viel tun und außerhalb des Bereichs der Klasse liegen .
Manchmal finde ich auch, dass ich einen Test schreibe, der im Moment zu groß ist, um ihn zu kauen, und deshalb denke ich, "eh, ich werde später auf diesen Test zurückkommen, wenn ich mehr API zum Arbeiten habe" (I. Ich werde es auskommentieren und im Hinterkopf behalten. Hier werden viele Entwickler, die ich getroffen habe, dann Tests für ihre private Funktionalität schreiben und TDD als Sündenbock verwenden. Sie sagen: "Oh, nun, ich brauche einen anderen Test, aber um diesen Test zu schreiben, brauche ich diese privaten Methoden. Da ich keinen Produktionscode schreiben kann, ohne einen Test zu schreiben, muss ich einen Test schreiben für eine private Methode. " Was sie jedoch wirklich tun müssen, ist die Umgestaltung in kleinere und wiederverwendbare Komponenten, anstatt ihrer aktuellen Klasse eine Reihe privater Methoden hinzuzufügen / zu testen.
Hinweis:
Ich habe vor einiger Zeit eine ähnliche Frage zum Testen privater Methoden mit GoogleTest beantwortet . Ich habe diese Antwort größtenteils geändert, um hier sprachunabhängiger zu sein.
PS Hier ist die relevante Vorlesung über Eisbergklassen und Greifwerkzeuge von Michael Feathers: https://www.youtube.com/watch?v=4cVZvoFGJTU
quelle
_
, bedeutet dies "hey, dies ist" privat ". Sie können es verwenden, aber vollständige Offenlegung, es wurde nicht für die Wiederverwendung entwickelt und Sie sollten es nur verwenden, wenn Sie es wirklich tun weiß was du tust ". Sie können in jeder Sprache den gleichen Ansatz verfolgen: Machen Sie diese Mitglieder öffentlich, markieren Sie sie jedoch mit einem führenden Zeichen_
. Oder vielleicht sollten diese Funktionen wirklich privat sein und nur über eine öffentliche Schnittstelle getestet werden (siehe Antwort für weitere Details). Es ist von Fall zu Fall keine allgemeine RegelIch denke, es ist am besten, nur die öffentliche Schnittstelle eines Objekts zu testen. Aus Sicht der Außenwelt ist nur das Verhalten der öffentlichen Schnittstelle von Bedeutung, und darauf sollten Ihre Unit-Tests ausgerichtet sein.
Sobald Sie einige solide Komponententests für ein Objekt geschrieben haben, möchten Sie nicht mehr zurückgehen und diese Tests ändern müssen, nur weil sich die Implementierung hinter der Schnittstelle geändert hat. In dieser Situation haben Sie die Konsistenz Ihrer Unit-Tests ruiniert.
quelle
Wenn Ihre private Methode nicht durch Aufrufen Ihrer öffentlichen Methoden getestet wird, was macht sie dann? Ich spreche privat nicht geschützt oder Freund.
quelle
Wenn die private Methode gut definiert ist (dh eine Funktion hat, die testbar ist und sich im Laufe der Zeit nicht ändern soll), dann ja. Ich teste alles, was testbar ist, wo es Sinn macht.
Beispielsweise kann eine Verschlüsselungsbibliothek die Tatsache verbergen, dass sie eine Blockverschlüsselung mit einer privaten Methode durchführt, die jeweils nur 8 Bytes verschlüsselt. Ich würde einen Unit-Test dafür schreiben - er soll sich nicht ändern, obwohl er versteckt ist, und wenn er kaputt geht (zum Beispiel aufgrund zukünftiger Leistungsverbesserungen), möchte ich wissen, dass nicht nur die private Funktion kaputt gegangen ist dass eine der öffentlichen Funktionen brach.
Es beschleunigt das spätere Debuggen.
-Adam
quelle
Wenn Sie Test Driven (TDD) entwickeln, testen Sie Ihre privaten Methoden.
quelle
Ich bin kein Experte auf diesem Gebiet, aber Unit-Tests sollten das Verhalten und nicht die Implementierung testen. Private Methoden sind ausschließlich Teil der Implementierung, daher sollte IMHO nicht getestet werden.
quelle
Wir testen private Methoden durch Inferenz, womit ich meine, dass wir eine Gesamttestabdeckung von mindestens 95% anstreben, aber unsere Tests nur öffentliche oder interne Methoden aufrufen. Um die Abdeckung zu erhalten, müssen wir mehrere Anrufe bei der Öffentlichkeit / den Interna tätigen, basierend auf den verschiedenen Szenarien, die auftreten können. Dies macht unsere Tests zielgerichteter in Bezug auf den Zweck des Codes, den sie testen.
Trumpis Antwort auf den von Ihnen verlinkten Beitrag ist die beste.
quelle
Unit-Tests dienen meiner Meinung nach zum Testen öffentlicher Methoden. Ihre öffentlichen Methoden verwenden Ihre privaten Methoden, sodass sie indirekt auch getestet werden.
quelle
Ich habe mich eine Weile mit diesem Thema beschäftigt, vor allem, weil ich mich bei TDD versucht habe.
Ich bin auf zwei Beiträge gestoßen, die meines Erachtens dieses Problem im Fall von TDD gründlich genug angehen.
Zusammenfassend:
Bei Verwendung testgetriebener Entwicklungstechniken (Design) sollten private Methoden nur während des Re-Factoring-Prozesses von bereits funktionierendem und getestetem Code entstehen.
Aufgrund der Natur des Prozesses wird jede einfache Implementierungsfunktionalität, die aus einer gründlich getesteten Funktion extrahiert wird, selbst getestet (dh indirekte Testabdeckung).
Mir scheint klar genug zu sein, dass die meisten Methoden zu Beginn der Codierung Funktionen auf höherer Ebene sein werden, da sie das Design kapseln / beschreiben.
Daher werden diese Methoden öffentlich sein und das Testen wird einfach genug sein.
Die privaten Methoden werden später verfügbar sein, sobald alles gut funktioniert und wir sie aus Gründen der Lesbarkeit und Sauberkeit neu faktorisieren .
quelle
Wie oben zitiert: "Wenn Sie Ihre privaten Methoden nicht testen, woher wissen Sie, dass sie nicht kaputt gehen?"
Dies ist ein großes Problem. Einer der großen Punkte bei Unit-Tests ist zu wissen, wo, wann und wie etwas so schnell wie möglich kaputt gegangen ist. Dadurch wird ein erheblicher Entwicklungs- und Qualitätssicherungsaufwand verringert. Wenn alles, was getestet wird, die Öffentlichkeit ist, haben Sie keine ehrliche Berichterstattung und Abgrenzung der Interna der Klasse.
Ich habe eine der besten Möglichkeiten gefunden, dies zu tun, indem ich einfach den Testverweis zum Projekt hinzufüge und die Tests in eine Klasse parallel zu den privaten Methoden einfüge. Geben Sie die entsprechende Build-Logik ein, damit die Tests nicht in das endgültige Projekt integriert werden.
Dann haben Sie alle Vorteile, diese Methoden testen zu lassen, und Sie können Probleme in Sekunden gegenüber Minuten oder Stunden finden.
Also zusammenfassend, ja, Unit-Test Ihrer privaten Methoden.
quelle
Das solltest du nicht . Wenn Ihre privaten Methoden eine ausreichende Komplexität aufweisen, die getestet werden muss, sollten Sie sie einer anderen Klasse zuordnen. Behalten Sie einen hohen Zusammenhalt bei , eine Klasse sollte nur einen Zweck haben. Die öffentliche Schnittstelle der Klasse sollte ausreichen.
quelle
Wenn Sie Ihre privaten Methoden nicht testen, woher wissen Sie, dass sie nicht kaputt gehen?
quelle
Es ist offensichtlich sprachabhängig. In der Vergangenheit habe ich mit c ++ die Testklasse als Freundklasse deklariert. Leider erfordert dies, dass Ihr Produktionscode über die Testklasse Bescheid weiß.
quelle
Ich verstehe den Standpunkt, dass private Methoden als Implementierungsdetails betrachtet werden und dann nicht getestet werden müssen. Und ich würde mich an diese Regel halten, wenn wir uns nur außerhalb des Objekts entwickeln müssten. Aber sind wir eine Art eingeschränkter Entwickler, die sich nur außerhalb von Objekten entwickeln und nur ihre öffentlichen Methoden aufrufen? Oder entwickeln wir dieses Objekt tatsächlich auch? Da wir nicht verpflichtet sind, externe Objekte zu programmieren, müssen wir diese privaten Methoden wahrscheinlich in neue öffentliche Methoden aufrufen, die wir entwickeln. Wäre es nicht toll zu wissen, dass die private Methode allen Widrigkeiten widersteht?
Ich weiß, dass einige Leute antworten könnten, wenn wir eine andere öffentliche Methode für dieses Objekt entwickeln, sollte diese getestet werden und das war's (die private Methode könnte ohne Test weiterleben). Dies gilt jedoch auch für alle öffentlichen Methoden eines Objekts: Bei der Entwicklung einer Webanwendung werden alle öffentlichen Methoden eines Objekts von Controller-Methoden aufgerufen und können daher als Implementierungsdetails für Controller betrachtet werden.
Warum testen wir Objekte? Weil es wirklich schwierig ist, nicht unmöglich zu sagen, dass wir die Methoden der Controller mit der entsprechenden Eingabe testen, die alle Zweige des zugrunde liegenden Codes auslöst. Mit anderen Worten, je höher wir im Stapel sind, desto schwieriger ist es, das gesamte Verhalten zu testen. Dies gilt auch für private Methoden.
Für mich ist die Grenze zwischen privaten und öffentlichen Methoden ein psychologisches Kriterium, wenn es um Tests geht. Kriterien, die mir wichtiger sind, sind:
quelle
Wenn ich feststelle, dass die private Methode riesig oder komplex oder wichtig genug ist, um eigene Tests zu erfordern, stelle ich sie einfach in eine andere Klasse und mache sie dort öffentlich (Methodenobjekt). Dann kann ich leicht die zuvor private, aber jetzt öffentliche Methode testen, die jetzt in ihrer eigenen Klasse lebt.
quelle
Ich verstehe das Konzept des Unit Test nie, aber jetzt weiß ich, was das Ziel ist.
Ein Unit Test ist kein vollständiger Test . Es ist also kein Ersatz für QS und manuelle Tests. Das Konzept von TDD in diesem Aspekt ist falsch, da Sie nicht alles testen können, einschließlich privater Methoden, aber auch Methoden, die Ressourcen verwenden (insbesondere Ressourcen, auf die wir keinen Einfluss haben). TDD basiert auf all seiner Qualität, die nicht erreicht werden konnte.
Ein Unit-Test ist eher ein Pivot-Test. Sie markieren einen beliebigen Pivot und das Ergebnis des Pivots sollte gleich bleiben.
quelle
Öffentlich oder privat ist weder eine nützliche Unterscheidung für das, was apis aus Ihren Tests aufruft, noch Methode gegen Klasse. Die meisten testbaren Einheiten sind in einem Kontext sichtbar, in anderen jedoch verborgen.
Was zählt, ist Deckung und Kosten. Sie müssen die Kosten minimieren und gleichzeitig die Abdeckungsziele Ihres Projekts erreichen (Linie, Zweig, Pfad, Block, Methode, Klasse, Äquivalenzklasse, Anwendungsfall ... was auch immer das Team entscheidet).
Verwenden Sie daher Tools, um die Abdeckung sicherzustellen, und gestalten Sie Ihre Tests so, dass sie die geringsten Kosten verursachen (kurz- und langfristig ).
Machen Sie Tests nicht teurer als nötig. Wenn es am billigsten ist, nur öffentliche Einstiegspunkte zu testen, tun Sie dies. Wenn es am billigsten ist, private Methoden zu testen, tun Sie das.
Je erfahrener Sie werden, desto besser können Sie vorhersagen, wann es sich lohnt, eine Umgestaltung vorzunehmen, um langfristige Kosten für die Testwartung zu vermeiden.
quelle
Wenn die Methode signifikant genug / komplex genug ist, mache ich sie normalerweise "geschützt" und teste sie. Einige Methoden werden privat gelassen und implizit im Rahmen von Unit-Tests für die öffentlichen / geschützten Methoden getestet.
quelle
Ich sehe, dass viele Menschen in der gleichen Denkweise sind: Test auf öffentlicher Ebene. Aber ist es nicht das, was unser QA-Team tut? Sie testen die Eingabe und die erwartete Ausgabe. Wenn wir als Entwickler nur die öffentlichen Methoden testen, wiederholen wir einfach den Job von QA und fügen durch "Unit-Tests" keinen Mehrwert hinzu.
quelle
Die Antwort auf "Soll ich private Methoden testen?" ist manchmal". Normalerweise sollten Sie anhand der Schnittstelle Ihrer Klassen testen.
Hier ist ein Beispiel:
In
RefactoredThing
Sie haben nun 5 Tests, von denen 2 Sie Refactoring aktualisieren musste, aber das Objekt Funktionalität wirklich nicht geändert hat. Nehmen wir also an, die Dinge sind komplexer als das und Sie haben eine Methode, die die Reihenfolge der Ausgabe definiert, wie zum Beispiel:Dies sollte nicht von einem externen Benutzer ausgeführt werden, aber Ihre Kapselungsklasse ist möglicherweise zu schwer, um so viel Logik immer wieder auszuführen. In diesem Fall möchten Sie dies vielleicht lieber in eine separate Klasse extrahieren, dieser Klasse eine Schnittstelle geben und dagegen testen.
Nehmen wir zum Schluss an, Ihr Hauptobjekt ist sehr schwer, die Methode ist recht klein und Sie müssen wirklich sicherstellen, dass die Ausgabe korrekt ist. Sie denken: "Ich muss diese private Methode testen!". Haben Sie das, dass Sie Ihr Objekt vielleicht leichter machen können, indem Sie einen Teil der schweren Arbeit als Initialisierungsparameter übergeben? Dann können Sie etwas Leichteres hineingeben und dagegen testen.
quelle
Nein Sie sollten die privaten Methoden nicht testen, warum? Darüber hinaus bietet das beliebte Mocking-Framework wie Mockito keine Unterstützung für das Testen privater Methoden.
quelle
Ein Hauptpunkt ist
Wenn wir testen, um die Richtigkeit der Logik sicherzustellen, und eine private Methode eine Logik enthält, sollten wir sie testen. Ist es nicht? Warum überspringen wir das?
Das Schreiben von Tests, die auf der Sichtbarkeit von Methoden basieren, ist völlig irrelevant.
Umgekehrt
Andererseits ist das Aufrufen einer privaten Methode außerhalb der ursprünglichen Klasse ein Hauptproblem. Außerdem gibt es in einigen Verspottungswerkzeugen Einschränkungen, eine private Methode zu verspotten. (Beispiel: Mockito )
Obwohl es einige Tools wie Power Mock gibt, die dies unterstützen, ist dies eine gefährliche Operation. Der Grund dafür ist, dass die JVM gehackt werden muss, um dies zu erreichen.
Eine Möglichkeit, dies zu umgehen, ist (wenn Sie Testfälle für private Methoden schreiben möchten)
Deklarieren Sie diese privaten Methoden als geschützt . In einigen Situationen ist dies jedoch möglicherweise nicht bequem.
quelle
Es geht nicht nur um öffentliche oder private Methoden oder Funktionen, sondern auch um Implementierungsdetails. Private Funktionen sind nur ein Aspekt der Implementierungsdetails.
Unit-Tests sind schließlich ein White-Box-Testansatz. Wer beispielsweise die Abdeckungsanalyse verwendet, um Teile des Codes zu identifizieren, die bisher beim Testen vernachlässigt wurden, geht auf die Implementierungsdetails ein.
A) Ja, Sie sollten die Implementierungsdetails testen:
Stellen Sie sich eine Sortierfunktion vor, die aus Leistungsgründen eine private Implementierung von BubbleSort verwendet, wenn bis zu 10 Elemente vorhanden sind, und eine private Implementierung eines anderen Sortieransatzes (z. B. Heapsort), wenn mehr als 10 Elemente vorhanden sind. Die öffentliche API ist die einer Sortierfunktion. Ihre Testsuite nutzt jedoch besser das Wissen, dass tatsächlich zwei Sortieralgorithmen verwendet werden.
In diesem Beispiel könnten Sie die Tests sicherlich für die öffentliche API durchführen. Dies würde jedoch eine Anzahl von Testfällen erfordern, die die Sortierfunktion mit mehr als 10 Elementen ausführen, so dass der Heapsort-Algorithmus ausreichend gut getestet ist. Das Vorhandensein solcher Testfälle allein ist ein Hinweis darauf, dass die Testsuite mit den Implementierungsdetails der Funktion verbunden ist.
Wenn sich die Implementierungsdetails der Sortierfunktion ändern, möglicherweise in der Weise, dass die Grenze zwischen den beiden Sortieralgorithmen verschoben wird oder Heapsort durch Mergesort oder was auch immer ersetzt wird: Die vorhandenen Tests funktionieren weiterhin. Ihr Wert ist dann jedoch fraglich, und sie müssen wahrscheinlich überarbeitet werden, um die geänderte Sortierfunktion besser testen zu können. Mit anderen Worten, es wird einen Wartungsaufwand geben, obwohl Tests auf der öffentlichen API durchgeführt wurden.
B) Testen der Implementierungsdetails
Ein Grund, warum viele Leute argumentieren, man sollte private Funktionen oder Implementierungsdetails nicht testen, ist, dass sich die Implementierungsdetails eher ändern. Diese höhere Wahrscheinlichkeit von Änderungen ist zumindest einer der Gründe dafür, Implementierungsdetails hinter Schnittstellen zu verbergen.
Angenommen, die Implementierung hinter der Schnittstelle enthält größere private Teile, für die einzelne Tests auf der internen Schnittstelle eine Option sein könnten. Einige Leute argumentieren, diese Teile sollten nicht getestet werden, wenn sie privat sind, sie sollten in etwas Öffentliches verwandelt werden. Einmal öffentlich, wäre es in Ordnung, diesen Code zu testen.
Dies ist interessant: Während die Schnittstelle intern war, wurde sie wahrscheinlich geändert, da es sich um ein Implementierungsdetail handelt. Wenn Sie dieselbe Schnittstelle verwenden und sie öffentlich machen, wird eine magische Transformation durchgeführt, nämlich die Umwandlung in eine Schnittstelle, die sich weniger wahrscheinlich ändert. Offensichtlich gibt es einen Fehler in dieser Argumentation.
Dahinter steckt jedoch eine gewisse Wahrheit: Beim Testen von Implementierungsdetails, insbesondere unter Verwendung interner Schnittstellen, sollte man sich bemühen, Schnittstellen zu verwenden, die wahrscheinlich stabil bleiben. Ob eine Schnittstelle wahrscheinlich stabil ist, kann jedoch nicht einfach anhand der öffentlichen oder privaten Schnittstelle entschieden werden. In den Projekten aus der Welt, in denen ich seit einiger Zeit arbeite, ändern sich auch die öffentlichen Schnittstellen oft genug, und viele private Schnittstellen sind seit Ewigkeiten unberührt geblieben.
Dennoch ist es eine gute Faustregel, die "Haustür zuerst" zu verwenden (siehe http://xunitpatterns.com/Principles%20of%20Test%20Automation.html) ). Aber denken Sie daran, dass es "Haustür zuerst" und nicht "Haustür nur" heißt.
C) Zusammenfassung
Testen Sie auch die Implementierungsdetails. Testen Sie lieber an stabilen Schnittstellen (öffentlich oder privat). Wenn sich die Implementierungsdetails ändern, müssen auch Tests der öffentlichen API überarbeitet werden. Etwas Privates in öffentliches zu verwandeln, verändert seine Stabilität nicht auf magische Weise.
quelle
Ja, Sie sollten nach Möglichkeit private Methoden testen. Warum? Um eine unnötige Explosion des Zustandsraums zu vermeiden von Testfällen im die letztendlich implizit dieselben privaten Funktionen wiederholt an denselben Eingaben testen. Lassen Sie uns anhand eines Beispiels erklären, warum.
Betrachten Sie das folgende leicht erfundene Beispiel. Angenommen, wir möchten eine Funktion öffentlich verfügbar machen, die 3 Ganzzahlen akzeptiert und nur dann true zurückgibt, wenn diese 3 Ganzzahlen alle Primzahlen sind. Wir könnten es so implementieren:
Wenn wir nun den strengen Ansatz verfolgen würden, dass nur öffentliche Funktionen getestet werden sollten, dürfen wir nur testen
allPrime
und nichtisPrime
oderandAll
.Als Tester, könnten wir in fünf Möglichkeiten für jedes Argument interessiert sein:
< 0
,= 0
,= 1
,prime > 1
,not prime > 1
. Aber um gründlich zu sein, müssten wir auch sehen, wie jede Kombination der Argumente zusammenspielt. So das ist5*5*5
= 125 Testfälle, die wir gemäß unserer Intuition gründlich testen müssten.Wenn wir andererseits die privaten Funktionen testen könnten, könnten wir mit weniger Testfällen so viel Boden abdecken. Wir würden nur 5 Testfälle benötigen, um
isPrime
auf dem gleichen Niveau wie unsere vorherige Intuition zu testen . Und nach der von Daniel Jackson vorgeschlagenen Small-Scope-Hypothese müssten wir dieandAll
Funktion nur bis zu einer kleinen Länge testen, z. B. 3 oder 4. Das wären höchstens 16 weitere Tests. Also insgesamt 21 Tests. Anstelle von 125. Natürlich würden wir wahrscheinlich ein paar Tests durchführen wollenallPrime
, aber wir würden uns nicht so verpflichtet fühlen, alle 125 Kombinationen von Eingabeszenarien, von denen wir sagten, dass sie uns wichtig sind, ausführlich abzudecken. Nur ein paar glückliche Wege.Sicher ein erfundenes Beispiel, aber es war für eine klare Demonstration notwendig. Und das Muster erstreckt sich auf echte Software. Private Funktionen sind normalerweise die Bausteine der untersten Ebene und werden daher häufig miteinander kombiniert, um eine Logik auf höherer Ebene zu erhalten. Das heißt, auf höheren Ebenen haben wir aufgrund der verschiedenen Kombinationen mehr Wiederholungen der Sachen auf niedrigeren Ebenen.
quelle
isPrime
sind wirklich unabhängig, daher ist es ziemlich zwecklos, jede Kombination blind zu testen. ZweitensisPrime
verstößt das Markieren einer reinen Funktion namens privat gegen so viele Entwurfsregeln, dass ich nicht einmal weiß, wo ich anfangen soll.isPrime
sollte ganz klar eine öffentliche Funktion sein. Davon abgesehen verstehe ich, was Sie sagen, ungeachtet dieses extrem schlechten Beispiels. Es basiert jedoch auf der Voraussetzung, dass Sie Kombinationstests durchführen möchten , wenn dies in realen Softwaresystemen selten eine gute Idee ist.Sie können Ihre Methode auch als privat festlegen, dh als Standard, und Sie sollten in der Lage sein, sie einem Komponententest zu unterziehen, es sei denn, sie muss privat sein.
quelle