Ich mache meine ersten Schritte mit Komponententests und habe ein Problem mit der Kapselung. Meine Klasse hat einige private Member-Variablen, die für den Client nicht sichtbar sein sollten, aber damit ich das Objekt in einen Zustand versetzen kann, unter dem ich es testen möchte, muss ich diese privaten Variablen setzen.
Sagen Sie, ich habe einen Code wie diesen:
%Vor% Nun möchte ich Foo::action()
testen, aber ich muss Foo::state
einstellen können, um die Funktion in verschiedenen Szenarien überprüfen zu können. Eine Lösung ist das böse " define private public
" im Testcode. Aber gibt es etwas Eleganteres? Ich möchte betonen, dass Foo::state
eine Variable ist, auf die der Client nicht zugreifen sollte, deshalb möchte ich keinen öffentlichen Setter deklarieren.
Bearbeiten:
Ich denke jetzt, dass die Erweiterung der Klasse, die ich in Testcode testen möchte, und das Einfügen von Setter in diese abgeleitete Klasse funktionieren würde, vorausgesetzt, ich habe private Variablen in protected geändert. Aber das ist eine "one generation only" -Lösung und fühlt sich immer noch eher wie ein Hack an als ein richtiger Ansatz.
Bearbeiten 2:
Nachdem ich die Antworten und Kommentare gelesen hatte (danke an Lieven und insbesondere ap) glaube ich, dass die eigentliche Klasse, die ich jetzt testen möchte (nicht das einfache Beispiel, das ich zur Verfügung gestellt habe), einfach zu viel und die Antwort auf meine Problem ist das Verschieben einiger seiner Logik in eine andere Klasse, die von dem großen Kerl verwendet wird.
Es gibt nur zwei Möglichkeiten (refactoring asside)
Option 2 ist selbsterklärend und höchstwahrscheinlich nicht auf Ihren Fall anwendbar, so dass Sie den Status über die öffentliche Schnittstelle Ihrer Klasse festlegen müssen.
Wie Sie bereits erwähnt haben, ist dies möglich, aber es erfordert viel Code, um in den richtigen Zustand zu gelangen. Das kann ein Hinweis darauf sein, dass Ihre Klasse gerade zu viel tut, und es ist an der Zeit, Teile Ihrer Klasse in kleinere, testbare Klassen umzuformen.
Von Testen Sie keine privaten Methoden
Wenn Sie das Bedürfnis haben, eine private Methode zu testen, dann tun Sie es etwas anderes stimmt nicht. Es gibt sozusagen ein "Upstream" -Problem. Sie sind aufgrund eines anderen Fehlers in diesem Problem angekommen dieser Prozess. Versuche zu isolieren, was genau ist, und entferne das anstatt Ihre Tests zu beugen, um eine schmerzhafte Straße von zu gehen Sprödigkeit beim Testen.
und Unit testet private Mitglieder
Ich würde empfehlen, keine privaten Methoden zu testen. Da sind sie privat, sie können in jedem denkbaren (oder unvorstellbaren?) geändert werden Art und Weise zwischen jedem Release. Wenn eine bestimmte private Methode so kritisch ist zu der Operation der Klasse, die Sie fühlen, dass es Testfälle verdient, Dann ist es wahrscheinlich an der Zeit, das in ein geschütztes oder umgestaltetes zu verwandeln öffentliche Methode
Ein häufiges Zitat dazu ist
Sie sollten niemals Ihre Privatsphäre berühren
Sie sollten einen% code_% ly (oder " public
ly") Mechanismus haben, um den Wert der privaten Variable protected
zu ändern. Zur Einfachheit sagen wir, es ist eine Methode state
. Verwenden Sie diese im Komponententest, um den Status zu ändern, und testen Sie die Foo::setState(int inState)
-Methode. Dies stellt sicher, dass zukünftige Implementierungsänderungen den Komponententest nicht beeinflussen (es sei denn, die "API" Foo::action()
ändert sich - in diesem Fall müssen Sie natürlich den Komponententest ändern).
Wenn Sie nicht einen solchen Mechanismus zum Ändern von Foo::setState()
haben, bedeutet dies, dass der Endbenutzer oder der aufrufende Code sie auch nicht ändern kann und Sie ihn daher nicht testen müssen (und vielleicht macht das state
überflüssig, aber das weiß ich nicht.)
Wenn sich die private Variable "indirekt" durch anderen Code ändert, müssen Sie denselben Code im Komponententest ausführen. Sie können jederzeit jede extern sichtbare Methode auf Eingänge zurückführen, die dem Code extern zugeführt wurden. Grundsätzlich ist der Punkt, dass Sie im Komponententest dieselben Eingaben wie im "echten" Szenario dem Code zuführen müssen und dann testen müssen, ob er so reagiert wie er sollte.
Wenn der "Pfad" von der Eingabe zum zu testenden Code too lang ist, muss der Code / Test möglicherweise in kleinere Module oder Zwischenpunkte zerlegt werden. Um dies näher auszuführen, betrachten Sie den Code-Fluss als:
%Vor%Im obigen Fall ist alles, was Sie tun können,
Gegeben
state
, überprüfe obInput
korrekt ist.
Stattdessen wäre es gut, das intermediate Output
, A
, B
zumindest für die Komponententests verfügbar zu machen, so dass Sie jetzt Ihren Test in:
Gegeben
C
, überprüfe obInput
korrekt ist.Gegeben
A
, überprüfe obA
korrekt ist.Gegeben
B
, überprüfe obB
korrekt ist.Gegeben
C
, überprüfe obC
korrekt ist.
Wie Sie sich vorstellen können, wird es bei einem fehlgeschlagenen Test einfacher, herauszufinden, was fehlgeschlagen ist, und es somit zu beheben.
Tags und Links unit-testing c++