Sollte ich private Methoden vermeiden, wenn ich TDD durchführe?

100

Ich lerne gerade TDD. Nach meinem Verständnis sind private Methoden nicht testbar und sollten nicht besorgt sein, da die öffentliche API genügend Informationen zur Überprüfung der Objektintegrität bereitstellt.

Ich habe OOP für eine Weile verstanden. Ich verstehe, dass private Methoden Objekte gekapselter machen und somit Änderungen und Fehlern widerstehen. Sie sollten daher standardmäßig verwendet werden und nur die für Clients wichtigen Methoden sollten veröffentlicht werden.

Nun, es ist mir möglich, ein Objekt zu erstellen, das nur über private Methoden verfügt und mit anderen Objekten interagiert, indem ich deren Ereignisse abhöre. Dies wäre sehr gekapselt, aber völlig unprüfbar.

Es wird auch als schlechte Praxis angesehen, Methoden zu Testzwecken hinzuzufügen.

Bedeutet dies, dass TDD im Widerspruch zur Kapselung steht? Was ist das richtige Gleichgewicht? Ich bin geneigt, die meisten oder alle meiner Methoden jetzt zu veröffentlichen ...

Welpe
quelle
9
Schlechte Praxis und Realität in der Software-Branche sind verschiedene Tiere. Eine ideale Situation ist häufig eine verzerrte Realität in der Geschäftswelt. Tun Sie, was Sinn macht, und halten Sie sich während der gesamten Anwendung daran. Ich hätte lieber ein schlechtes Training als den Geschmack des Monats, der sich über die Anwendung ausbreitet.
Aaron McIver
10
"Private Methoden sind nicht testbar"? Welche Sprache? In einigen Sprachen ist es unpraktisch. In anderen Sprachen ist es ganz einfach. Wollen Sie damit auch sagen, dass das Entwurfsprinzip der Kapselung immer mit vielen privaten Methoden implementiert werden muss ? Das scheint ein bisschen extrem. Einige Sprachen haben keine privaten Methoden, scheinen jedoch gut gekapselte Designs zu haben.
S.Lott
"Ich verstehe, dass private Methoden Objekte besser einkapseln und somit Änderungen und Fehlern widerstehen. Daher sollten sie standardmäßig verwendet werden und nur die Methoden, die für Clients von Bedeutung sind, sollten veröffentlicht werden." Dies scheint mir eine Gegenüberstellung dessen zu sein, was TDD erreichen will. TDD ist eine Entwicklungsmethode , mit der Sie ein einfaches, praktikables und für Änderungen offenes Design erstellen können. Wenn Sie "von privat" und "nur werben ..." suchen, wird dies vollständig umgekehrt. Vergessen Sie, es gibt so etwas wie eine private Methode, um TDD anzunehmen. Tun Sie sie später nach Bedarf. als Teil des Refactorings.
Herby
Mögliches Duplikat des Testens privater Methoden als geschützt
Gnat
@Gnat Sie denken, dies sollte als ein Duplikat der Frage geschlossen werden, die aus meiner Antwort auf diese Frage entstanden ist? * 8 ')
Mark Booth

Antworten:

50

Ziehen Sie das Testen der Schnittstelle dem Testen der Implementierung vor.

Ich verstehe, dass private Methoden nicht testbar sind

Dies hängt von Ihrer Entwicklungsumgebung ab (siehe unten).

[Private Methoden] sollten sich keine Sorgen machen, da die öffentliche API genügend Informationen zur Überprüfung der Objektintegrität bereitstellt.

Richtig, TDD konzentriert sich auf das Testen der Schnittstelle.

Private Methoden sind ein Implementierungsdetail, das sich während eines Re-Faktor-Zyklus ändern kann. Es sollte möglich sein, Änderungen vorzunehmen, ohne die Benutzeroberfläche oder das Black-Box- Verhalten zu ändern . Tatsächlich ist dies Teil des Vorteils von TDD. Die Leichtigkeit, mit der Sie das Vertrauen erzeugen können, dass sich klasseninterne Änderungen ergeben, wirkt sich nicht auf Benutzer dieser Klasse aus.

Nun, es ist mir möglich, ein Objekt zu erstellen, das nur über private Methoden verfügt und mit anderen Objekten interagiert, indem ich deren Ereignisse abhöre. Dies wäre sehr gekapselt, aber völlig unprüfbar.

Auch wenn die Klasse über keine öffentlichen Methoden verfügt, sind die Event-Handler die öffentlichen Schnittstellen , und sie richten sich gegen diese öffentlichen Schnittstellen , die Sie testen können.

Da die Ereignisse die Schnittstelle sind, müssen Sie diese Ereignisse generieren, um das Objekt zu testen.

Prüfen Sie, ob Sie Scheinobjekte als Klebstoff für Ihr Testsystem verwenden können. Es sollte möglich sein, ein einfaches Mock-Objekt zu erstellen, das ein Ereignis generiert und die resultierende Statusänderung aufnimmt (möglich durch ein anderes Empfänger-Mock-Objekt).

Es wird auch als schlechte Praxis angesehen, Methoden zu Testzwecken hinzuzufügen.

Auf jeden Fall sollten Sie sehr vorsichtig sein , wenn Sie den internen Zustand offenlegen .

Bedeutet dies, dass TDD im Widerspruch zur Kapselung steht? Was ist das richtige Gleichgewicht?

Absolut nicht.

TDD sollte die Implementierung Ihrer Klassen nur ändern, um sie zu vereinfachen (indem Sie YAGNI von einem früheren Punkt aus anwenden ).

Best Practice mit TDD ist identisch mit Best Practice ohne TDD. Sie müssen nur herausfinden, warum dies früher der Fall ist, da Sie die Benutzeroberfläche während der Entwicklung verwenden.

Ich bin geneigt, die meisten oder alle meiner Methoden jetzt zu veröffentlichen ...

Dies würde eher das Baby mit dem Badewasser werfen.

Sie sollten nicht müssen alle Methoden öffentlich zu machen, so dass Sie in einem TDD - Weise entwickeln können. Sehen Sie sich meine Notizen unten an, um zu sehen, ob Ihre privaten Methoden wirklich nicht testbar sind.

Ein detaillierterer Blick auf das Testen privater Methoden

Wenn Sie unbedingt ein privates Verhalten einer Klasse testen müssen , haben Sie je nach Sprache / Umgebung drei Möglichkeiten:

  1. Ordnen Sie die Tests der Klasse zu, die Sie testen möchten.
  2. Fügen Sie die Tests in eine andere Klassen- / Quelldatei ein und legen Sie die privaten Methoden, die Sie testen möchten, als öffentliche Methoden offen.
  3. Verwenden Sie eine Testumgebung, mit der Sie Test- und Produktionscode getrennt halten und dennoch den Testcode-Zugriff auf private Methoden des Produktionscodes ermöglichen können.

Offensichtlich ist die 3. Option bei weitem die beste.

1) Ordnen Sie die Tests der Klasse zu, die Sie testen möchten (nicht ideal).

Das Speichern von Testfällen in derselben Klasse / Quelldatei wie der zu testende Produktionscode ist die einfachste Option. Ohne viele Pre-Prozessor-Direktiven oder -Anmerkungen wird Ihr Testcode jedoch unnötigerweise aufgebläht, und je nachdem, wie Sie Ihren Code strukturiert haben, können Sie den Benutzern dieses Codes versehentlich die interne Implementierung zugänglich machen.

2) Machen Sie die privaten Methoden, die Sie testen möchten, als öffentliche Methoden verfügbar (wirklich keine gute Idee).

Wie bereits erwähnt, handelt es sich hierbei um eine sehr schlechte Praxis, die die Kapselung zerstört und die interne Implementierung für Benutzer des Codes verfügbar macht.

3) Verwenden Sie eine bessere Testumgebung (beste Option, falls verfügbar)

In der Eclipse-Welt kann 3. durch die Verwendung von Fragmenten erreicht werden . In der C # Welt könnten wir verwenden Teilklassen . Andere Sprachen / Umgebungen verfügen häufig über ähnliche Funktionen. Sie müssen sie nur finden.

Die blinde Annahme, dass 1. oder 2. die einzigen Optionen sind, würde wahrscheinlich dazu führen, dass die Produktionssoftware mit Testcode oder bösen Schnittstellen vollgestopft ist, die ihre schmutzige Wäsche in der Öffentlichkeit waschen. * 8 ')

  • Alles in allem ist es jedoch viel besser, nicht gegen eine private Implementierung zu testen.
Mark Booth
quelle
5
Ich bin mir nicht sicher, ob ich einer der drei von Ihnen vorgeschlagenen Optionen zustimmen würde. Ich würde es vorziehen, nur die öffentliche Schnittstelle zu testen, wie Sie zuvor sagten, aber sicherzustellen, dass auf diese Weise private Methoden ausgeübt werden. Ein Teil des Vorteils besteht darin, toten Code zu finden. Dies ist unwahrscheinlich, wenn Sie Ihren Testcode zwingen, die normale Verwendung der Sprache zu brechen.
Magus
Ihre Methoden sollten eine Sache tun, und ein Test sollte die Implementierung in keiner Weise berücksichtigen. Private Methoden sind Implementierungsdetails. Wenn das Testen nur mit öffentlichen Methoden bedeutet, dass es sich bei Ihren Tests um Integrationstests handelt, liegt ein Entwurfsproblem vor.
Magus
Wie wäre es, wenn Sie die Methode als Standard / geschützt festlegen und einen Test in einem Testprojekt mit demselben Paket erstellen?
RichardCypher
@RichardCypher Das ist praktisch dasselbe wie 2), da Sie Ihre Methodenspezifikationen idealerweise ändern, um einen Mangel in Ihrer Testumgebung auszugleichen, also definitiv immer noch schlechte Praxis.
Mark Booth
75

Natürlich können Sie private Methoden haben und natürlich können Sie sie testen.

Entweder gibt es eine Möglichkeit, die private Methode zum Laufen zu bringen. In diesem Fall können Sie sie auf diese Weise testen, oder es gibt keine Möglichkeit , die private Methode zum Laufen zu bringen. In diesem Fall: Warum zum Teufel versuchen Sie es nur zu testen? lösche das verdammte Ding!

In deinem Beispiel:

Nun, es ist mir möglich, ein Objekt zu erstellen, das nur über private Methoden verfügt und mit anderen Objekten interagiert, indem ich deren Ereignisse abhöre. Dies wäre sehr gekapselt, aber völlig unprüfbar.

Warum wäre das nicht testbar? Wenn die Methode als Reaktion auf ein Ereignis aufgerufen wird, muss der Test dem Objekt nur ein geeignetes Ereignis zuführen.

Es geht nicht darum, keine privaten Methoden zu haben, es geht darum, die Kapselung nicht zu brechen. Sie können über private Methoden verfügen, sollten diese jedoch über die öffentliche API testen. Wenn die öffentliche API auf Ereignissen basiert, verwenden Sie Ereignisse.

Für den allgemeineren Fall von privaten Hilfsmethoden können sie mit den öffentlichen Methoden getestet werden, die sie aufrufen. Insbesondere, da Sie nur Code schreiben dürfen, um einen fehlgeschlagenen Test zu bestehen, und Ihre Tests die öffentliche API testen, wird jeder neue Code, den Sie schreiben, normalerweise öffentlich sein. Private Methoden werden nur als Ergebnis eines Extract Method Refactorings angezeigt , wenn sie aus einer bereits vorhandenen öffentlichen Methode entfernt werden. In diesem Fall deckt der ursprüngliche Test, der die öffentliche Methode testet, auch die private Methode ab, da die öffentliche Methode die private Methode aufruft.

Daher erscheinen private Methoden in der Regel nur, wenn sie aus bereits getesteten öffentlichen Methoden extrahiert und somit auch bereits getestet wurden.

Jörg W. Mittag
quelle
3
Das Testen mit öffentlichen Methoden funktioniert in 99% der Fälle. Die Herausforderung ist die 1% der Zeit, in der Ihre einzelne öffentliche Methode mehrere hundert oder tausend Zeilen komplexen Codes enthält und alle Zwischenzustände implementierungsspezifisch sind. Sobald es komplex genug wird, wird es bestenfalls schmerzhaft, zu versuchen, alle Randfälle der öffentlichen Methode zu treffen. Alternativ dazu führt das Testen der Edge-Fälle, indem entweder die Kapselung aufgehoben und mehr Methoden als privat verfügbar gemacht werden, oder indem ein Kludge verwendet wird, damit die Tests private Methoden direkt aufrufen, dazu, dass Testfälle nicht nur hässlich, sondern auch spröde werden.
Dan Neely
24
Große, komplexe private Methoden sind ein Codegeruch. Eine Implementierung, die so komplex ist, dass sie nicht sinnvoll in Komponententeile (mit öffentlichen Schnittstellen) zerlegt werden kann, ist ein Testproblem, das potenzielle Design- und Architekturprobleme aufdeckt. Die 1% der Fälle, in denen der private Code sehr groß ist, profitieren normalerweise von Überarbeitungen zum Zerlegen und Belichten.
S.Lott
13
@Dan Neely-Code wie dieser ist ohnehin ziemlich unprüfbar - und ein Teil des Schreibens von Unit-Tests weist darauf hin. Beseitigen Sie Zustände, teilen Sie Klassen auf, wenden Sie alle typischen Refactorings an und schreiben Sie dann Komponententests. Wie sind Sie bei TDD überhaupt dazu gekommen? Dies ist einer der Vorteile von TDD, da das Schreiben von testbarem Code automatisch erfolgt.
Bill K
Zumindest internalMethoden oder öffentliche Methoden in internalKlassen sollten ziemlich oft direkt getestet werden. Glücklicherweise unterstützt .net die InternalsVisibleToAttribute, aber ohne sie wäre das Testen dieser Methode eine PITA.
CodesInChaos
25

Wenn Sie eine neue Klasse in Ihrem Code erstellen, tun Sie dies, um einige Anforderungen zu erfüllen. Die Anforderungen legen fest, was der Code tun muss, nicht wie . Dies macht es leicht verständlich, warum die meisten Tests auf der Ebene öffentlicher Methoden stattfinden.

Durch Tests stellen wir sicher, dass der Code das tut, was erwartet wird, löst entsprechende Ausnahmen aus, wenn erwartet, usw. Es ist uns egal, wie der Code vom Entwickler implementiert wird. Die Implementierung, dh die Funktionsweise des Codes, ist uns egal. Es ist jedoch sinnvoll, private Methoden nicht zu testen.

Wenn Sie Klassen testen möchten, die keine öffentlichen Methoden haben und nur durch Ereignisse mit der Außenwelt interagieren, können Sie dies auch testen, indem Sie die Ereignisse durch Tests senden und die Antwort abhören. Wenn eine Klasse beispielsweise jedes Mal, wenn sie ein Ereignis empfängt, eine Protokolldatei speichern muss, sendet der Komponententest das Ereignis und überprüft, ob die Protokolldatei geschrieben wurde.

Last but not least ist es in einigen Fällen durchaus sinnvoll, private Methoden zu testen. Aus diesem Grund können Sie beispielsweise in .NET nicht nur öffentliche, sondern auch private Klassen testen, auch wenn die Lösung nicht so einfach ist wie bei öffentlichen Methoden.

Arseni Mourzenko
quelle
4
+1 Ein wichtiges Merkmal von TDD ist, dass Sie dazu gezwungen werden, zu testen, ob die ANFORDERUNGEN erfüllt sind, anstatt zu testen, ob METHODEN das tun, was sie von Ihnen erwarten. Die Frage "Kann ich eine private Methode testen?" Widerspricht dem Geist von TDD. Stattdessen könnte die Frage "Kann ich eine Anforderung testen, deren Implementierung private Methoden enthält?" Lauten. Und die Antwort auf diese Frage lautet eindeutig Ja.
Dawood ibn Kareem
6

Ich verstehe, dass private Methoden nicht testbar sind

Ich bin mit dieser Aussage nicht einverstanden, oder ich würde sagen, dass Sie private Methoden nicht direkt testen . Eine öffentliche Methode kann verschiedene private Methoden aufrufen. Vielleicht wollte der Autor "kleine" Methoden haben und extrahierte einen Teil des Codes in eine klug benannte private Methode.

Unabhängig davon, wie die öffentliche Methode geschrieben ist, sollte Ihr Testcode alle Pfade abdecken. Wenn Sie nach Ihren Tests feststellen, dass eine der Verzweigungsanweisungen (if / switch) in einer privaten Methode noch nie in Ihren Tests behandelt wurde, liegt ein Problem vor. Entweder haben Sie einen Fall verpasst und die Implementierung ist korrekt ODER die Implementierung ist falsch, und dieser Zweig hätte eigentlich nie existieren dürfen.

Deshalb benutze ich häufig Cobertura und NCover, um sicherzustellen, dass mein öffentlicher Methodentest auch private Methoden abdeckt. Fühlen Sie sich frei, gute OO-Objekte mit privaten Methoden zu schreiben, und lassen Sie TDD / Testing in solchen Angelegenheiten nicht zu.

Jalayn
quelle
5

Ihr Beispiel ist immer noch perfekt testbar, solange Sie Dependency Injection verwenden, um die Instanzen bereitzustellen, mit denen Ihr CUT interagiert. Dann können Sie einen Mock verwenden, die Ereignisse von Interesse generieren und dann beobachten, ob der CUT die richtigen Aktionen für seine Abhängigkeiten ausführt oder nicht.

Auf der anderen Seite können Sie, wenn Sie eine Sprache mit guter Veranstaltungsunterstützung haben, einen etwas anderen Weg einschlagen. Ich mag es nicht, wenn Objekte Ereignisse selbst abonnieren, sondern wenn die Factory, die das Objekt erstellt, Ereignisse mit den öffentlichen Methoden des Objekts verknüpft. Es ist einfacher zu testen und macht von außen sichtbar, für welche Arten von Ereignissen der CUT getestet werden muss.

Chris Pitman
quelle
Das ist eine großartige Idee ... "... die Factory, die das Objekt erstellt, Ereignisse mit den öffentlichen Methoden des Objekts verkabeln zu lassen. Es ist einfacher zu testen und macht von außen sichtbar, auf welche Arten von Ereignissen das CUT getestet werden muss. "
Welpe
5

Sie sollten nicht mit privaten Methoden aufgeben müssen. Es ist durchaus vernünftig, sie zu verwenden, aber aus Sicht der Tests ist es schwieriger, sie direkt zu testen, ohne die Kapselung zu beschädigen oder Ihren Klassen testspezifischen Code hinzuzufügen. Der Trick besteht darin, die Dinge zu minimieren, von denen Sie wissen, dass sie Ihren Darm winden lassen, weil Sie das Gefühl haben, Sie hätten Ihren Code verschmutzt.

Dies sind die Dinge, an die ich denke, um ein funktionierendes Gleichgewicht zu erreichen.

  1. Minimieren Sie die Anzahl der von Ihnen verwendeten privaten Methoden und Eigenschaften. Die meisten Dinge, die Sie in Ihrer Klasse erledigen müssen, müssen sowieso öffentlich zugänglich gemacht werden. Überlegen Sie sich also, ob Sie diese clevere Methode wirklich privat machen müssen.
  2. Minimieren Sie die Menge an Code in Ihren privaten Methoden - das sollten Sie auf jeden Fall tun - und testen Sie indirekt, wo Sie über das Verhalten anderer Methoden können. Sie erwarten niemals eine 100% ige Testabdeckung und müssen möglicherweise einige Werte über den Debugger überprüfen. Mit privaten Methoden können Ausnahmen einfach indirekt getestet werden. Private Eigenschaften müssen möglicherweise manuell oder mit einer anderen Methode getestet werden.
  3. Wenn indirekte oder manuelle Überprüfungen nicht gut zu Ihnen passen, fügen Sie ein geschütztes Ereignis hinzu und greifen Sie über ein Interface zu, um einige der privaten Dinge freizulegen. Dies "verbiegt" effektiv die Kapselungsregeln, vermeidet jedoch die Notwendigkeit, tatsächlich Code zu versenden, der Ihre Tests ausführt. Der Nachteil ist, dass dies zu einem kleinen zusätzlichen internen Code führen kann, um sicherzustellen, dass das Ereignis bei Bedarf ausgelöst wird.
  4. Wenn Sie der Meinung sind, dass eine öffentliche Methode nicht "sicher" genug ist, prüfen Sie, ob es Möglichkeiten gibt, eine Art Validierungsprozess in Ihre Methoden zu implementieren, um deren Verwendung einzuschränken. Während Sie darüber nachdenken, überlegen Sie sich wahrscheinlich, wie Sie Ihre Methoden besser implementieren können, oder Sie werden feststellen, dass eine andere Klasse Gestalt annimmt.
  5. Wenn Sie viele private Methoden haben, die "Zeug" für Ihre öffentlichen Methoden ausführen, wartet möglicherweise eine neue Klasse darauf, extrahiert zu werden. Sie können dies direkt als separate Klasse testen, aber als Verbund privat in der Klasse implementieren, die es verwendet.

Quer denken. Halten Sie Ihre Klassen und Methoden klein und verwenden Sie viel Komposition. Es klingt nach mehr Arbeit, aber am Ende werden Sie mehr individuell testbare Objekte haben, Ihre Tests werden einfacher sein, Sie werden mehr Möglichkeiten haben, einfache Mocks anstelle von echten, großen und komplexen Objekten zu verwenden, hoffentlich gut. faktorisierter und lose gekoppelter Code, und was noch wichtiger ist, Sie geben sich selbst mehr Optionen. Wenn Sie die Dinge klein halten, können Sie am Ende Zeit sparen, da Sie die Anzahl der Dinge reduzieren, die Sie für jede Klasse einzeln überprüfen müssen, und Sie reduzieren auf natürliche Weise die Code-Spaghetti, die manchmal auftreten können, wenn eine Klasse groß wird und viele hat Internes Verhalten von voneinander abhängigem Code.

S.Robins
quelle
4

Nun, es ist mir möglich, ein Objekt zu erstellen, das nur über private Methoden verfügt und mit anderen Objekten interagiert, indem ich deren Ereignisse abhöre. Dies wäre sehr gekapselt, aber völlig unprüfbar.

Wie reagiert dieses Objekt auf diese Ereignisse? Vermutlich muss es Methoden für andere Objekte aufrufen. Sie können es testen, indem Sie prüfen, ob diese Methoden aufgerufen werden. Lassen Sie es ein Scheinobjekt aufrufen, und dann können Sie leicht behaupten, dass es das tut, was Sie erwarten.

Das Problem ist, dass wir nur die Interaktion des Objekts mit anderen Objekten testen möchten. Es ist uns egal, was in einem Objekt vor sich geht. Also nein, Sie sollten keine öffentlichen Methoden mehr haben als zuvor.

Winston Ewert
quelle
4

Ich habe auch mit dem gleichen Problem zu kämpfen. Wirklich, der Weg, um es zu umgehen, ist folgender: Wie erwarten Sie, dass der Rest Ihres Programms mit dieser Klasse zusammenarbeitet? Testen Sie Ihre Klasse entsprechend. Dies zwingt Sie dazu, Ihre Klasse basierend auf der Art und Weise zu gestalten, wie der Rest des Programms mit ihr in Verbindung steht, und fördert in der Tat die Kapselung und das gute Design Ihrer Klasse.

Chance
quelle
3

Anstelle der privaten Verwendung Standardmodifikator. Dann können Sie diese Methoden einzeln testen, nicht nur in Verbindung mit öffentlichen Methoden. Dies setzt voraus, dass Ihre Tests dieselbe Paketstruktur haben wie Ihr Hauptcode.

siamii
quelle
... vorausgesetzt das ist Java.
Dawood ibn Kareem
oder internalin .net.
CodesInChaos
2

Einige private Methoden sind normalerweise kein Problem. Sie testen sie einfach über die öffentliche API, als ob der Code in Ihre öffentlichen Methoden eingebunden wäre. Ein Überschuss an privaten Methoden kann ein Zeichen für einen schlechten Zusammenhalt sein. Ihre Klasse sollte eine zusammenhängende Verantwortung haben, und oft machen die Leute Methoden privat, um den Anschein von Zusammenhalt zu erwecken, wo keiner wirklich existiert.

Möglicherweise verfügen Sie über einen Ereignishandler, der als Reaktion auf diese Ereignisse viele Datenbankaufrufe ausführt. Da es offensichtlich eine schlechte Praxis ist, einen Ereignishandler zu instanziieren, um Datenbankaufrufe durchzuführen, besteht die Versuchung darin, alle datenbankbezogenen Aufrufe als private Methoden zu definieren, wenn sie wirklich in eine separate Klasse gezogen werden sollten.

Karl Bielefeldt
quelle
2

Bedeutet dies, dass TDD im Widerspruch zur Kapselung steht? Was ist das richtige Gleichgewicht? Ich bin geneigt, die meisten oder alle meiner Methoden jetzt zu veröffentlichen.

TDD widerspricht nicht der Verkapselung. Nehmen Sie das einfachste Beispiel für eine Getter-Methode oder -Eigenschaft, je nachdem, welche Sprache Sie gewählt haben. Angenommen, ich habe ein Kundenobjekt und möchte, dass es ein ID-Feld enthält. Der erste Test, den ich schreiben werde, lautet "customer_id_initializes_to_zero". Ich definiere den Getter, um eine nicht implementierte Ausnahme auszulösen und zu beobachten, wie der Test fehlschlägt. Das Einfachste, was ich tun kann, um diesen Test zu bestehen, ist, den Getter auf Null zu setzen.

Von dort aus gehe ich zu anderen Tests über, bei denen die Kunden-ID vermutlich ein tatsächliches Funktionsfeld darstellt. Irgendwann muss ich wahrscheinlich ein privates Feld erstellen, das die Kundenklasse verwendet, um zu verfolgen, was vom Getter zurückgegeben werden soll. Wie genau verfolge ich das? Ist es ein einfaches Backing Int? Behalte ich einen String im Auge und konvertiere ihn dann in int? Behalte ich 20 Zoll im Auge und mittle sie? Die Außenwelt kümmert sich nicht darum - und Ihre TDD-Tests kümmern sich nicht darum. Das ist ein gekapseltes Detail.

Ich denke, dass dies beim Starten von TDD nicht immer sofort offensichtlich ist - Sie testen nicht, was Methoden intern tun - Sie testen weniger detaillierte Bedenken der Klasse. Sie möchten also nicht testen, ob diese Methode einen DoSomethingToFoo()Balken instanziiert, eine Methode darauf aufruft, zwei zu einer seiner Eigenschaften hinzufügt usw. Sie testen, ob sich nach dem Mutieren des Status Ihres Objekts ein Status-Accessor geändert hat (oder nicht). Das ist das allgemeine Muster Ihrer Tests: "Wenn ich mit meiner getesteten Klasse X mache, kann ich anschließend Y beobachten". Wie es zu Y kommt, ist kein Problem der Tests, und dies ist, was eingekapselt ist, und aus diesem Grund widerspricht TDD nicht der Einkapselung.

Erik Dietrich
quelle
2

Vermeide das Benutzen? Nein .
Vermeiden Sie mit Start ? Ja.

Ich stelle fest, dass Sie nicht gefragt haben, ob es in Ordnung ist, abstrakte Klassen mit TDD zu haben. Wenn Sie verstehen, wie abstrakte Klassen während der TDD entstehen, gilt das gleiche Prinzip auch für private Methoden.

Sie können Methoden in abstrakten Klassen nicht direkt testen, so wie Sie private Methoden nicht direkt testen können. Deshalb beginnen Sie nicht mit abstrakten Klassen und privaten Methoden. Sie beginnen mit konkreten Klassen und öffentlichen APIs und überarbeiten dann die allgemeinen Funktionen.


quelle