Entschuldigen Sie den Nekro in diesem Beitrag, aber ich fühle mich gezwungen, ein paar Dinge abzuwägen, die anscheinend nicht berührt wurden.
In erster Linie - wenn wir während des Unit-Tests Zugang zu privaten Mitgliedern einer Klasse benötigen, ist dies im Allgemeinen eine große, fette rote Fahne, die wir in unserem strategischen oder taktischen Ansatz vermasselt haben und versehentlich durch Druck auf das Prinzip der Einzelverantwortung verstoßen haben Verhalten, wo es nicht hingehört. Das Gefühl, auf Methoden zugreifen zu müssen, die eigentlich nichts anderes als eine isolierte Unterroutine eines Konstruktionsverfahrens sind, ist eines der häufigsten Ereignisse. Es ist jedoch so, als würde Ihr Chef erwarten, dass Sie bereit zur Arbeit erscheinen und auch pervers wissen müssen, welche Morgenroutine Sie durchlaufen haben, um in diesen Zustand zu gelangen ...
Das andere häufigste Beispiel dafür ist, dass Sie versuchen, die sprichwörtliche "Gottklasse" zu testen. Es ist an und für sich eine besondere Art von Problem, leidet jedoch unter dem gleichen Grundproblem, wenn man intime Details eines Verfahrens kennen muss - aber das kommt vom Thema ab.
In diesem speziellen Beispiel haben wir die Verantwortung für die vollständige Initialisierung des Bar-Objekts effektiv dem Konstruktor der FooBar-Klasse zugewiesen. Bei der objektorientierten Programmierung ist einer der Hauptgründe, dass der Konstruktor "heilig" ist und vor ungültigen Daten geschützt werden sollte, die seinen eigenen internen Zustand ungültig machen und ihn darauf vorbereiten würden, irgendwo anders stromabwärts zu versagen (in einer möglicherweise sehr tiefen Situation) Pipeline.)
Wir haben dies hier nicht getan, indem wir dem FooBar-Objekt erlaubt haben, einen Balken zu akzeptieren, der zum Zeitpunkt der Erstellung der FooBar noch nicht bereit ist, und dies durch eine Art "Hacking" des FooBar-Objekts kompensiert haben, um die Dinge selbst in die Hand zu nehmen Hände.
Dies ist das Ergebnis eines Versäumnisses, sich an einen anderen Tenent der objektorientierten Programmierung zu halten (im Fall von Bar). Dies bedeutet, dass der Status eines Objekts vollständig initialisiert und bereit sein sollte, eingehende Anrufe an seine öffentlichen Mitglieder unmittelbar nach der Erstellung zu verarbeiten. Dies bedeutet nicht, dass der Konstruktor in allen Fällen unmittelbar aufgerufen wird. Wenn Sie ein Objekt mit vielen komplexen Konstruktionsszenarien haben, ist es besser, Setter seinen optionalen Elementen einem Objekt auszusetzen, das gemäß einem Erstellungsentwurfsmuster (Factory, Builder usw.) in einem der folgenden Elemente implementiert ist die letzteren Fälle,
In Ihrem Beispiel scheint sich die Eigenschaft "status" der Leiste nicht in einem gültigen Zustand zu befinden, in dem eine FooBar sie akzeptieren kann. Die FooBar unternimmt also etwas, um dieses Problem zu beheben.
Das zweite Problem, das ich sehe, ist, dass Sie anscheinend versuchen, Ihren Code zu testen, anstatt eine testgetriebene Entwicklung zu üben. Dies ist definitiv meine eigene Meinung zu diesem Zeitpunkt; Aber diese Art des Testens ist wirklich ein Anti-Muster. Am Ende geraten Sie in die Falle, zu erkennen, dass Sie Kernprobleme beim Design haben, die verhindern, dass Ihr Code nachträglich testbar ist, anstatt die benötigten Tests zu schreiben und anschließend auf die Tests zu programmieren. In jedem Fall sollten Sie immer noch die gleiche Anzahl von Tests und Codezeilen haben, wenn Sie wirklich eine SOLID-Implementierung erreicht haben. Warum also versuchen, Ihren Weg in testbaren Code zurückzuentwickeln, wenn Sie die Angelegenheit zu Beginn Ihrer Entwicklungsbemühungen nur ansprechen können?
Wenn Sie das getan hätten, hätten Sie viel früher erkannt, dass Sie einen ziemlich ekligen Code schreiben müssten, um gegen Ihr Design zu testen, und hätten frühzeitig die Möglichkeit gehabt, Ihren Ansatz neu auszurichten, indem Sie das Verhalten auf Implementierungen verlagerten, die dies tun sind leicht testbar.