3227 Stimmen

Wie teste ich eine Klasse, die private Methoden, Felder oder innere Klassen hat?

Wie kann ich mit JUnit eine Klasse testen, die interne private Methoden, Felder oder verschachtelte Klassen hat?

Es scheint schlecht, den Zugriffsmodifikator für eine Methode zu ändern, nur um einen Test durchführen zu können.

327 Stimmen

Der beste Weg, eine private Methode zu testen, ist, sie nicht direkt zu testen

30 Stimmen

3 Stimmen

Warum sollte eine private Funktion getestet werden? Sie wird ohnehin automatisch getestet (und muss getestet werden), wenn Sie die Funktion/Methode testen, die die private Funktion verwendet.

1846voto

Cem Catikkas Punkte 7133

Aktualisierung:

Etwa 10 Jahre später ist der beste Weg zum Testen einer privaten Methode oder eines unzugänglichen Elements vielleicht die Verwendung von @Jailbreak von der Verteiler Rahmen.

@Jailbreak Foo foo = new Foo();
// Direct, *type-safe* access to *all* foo's members
foo.privateMethod(x, y, z);
foo.privateField = value;

Auf diese Weise bleibt Ihr Code typsicher und lesbar. Keine Kompromisse beim Design, keine Überbelichtung von Methoden und Feldern um der Tests willen.

Wenn Sie eine Art Erbe haben Java Anwendung, und Sie dürfen die Sichtbarkeit Ihrer Methoden nicht ändern, ist der beste Weg, um private Methoden zu testen, die Verwendung von Reflexion .

Intern verwenden wir Helfer zum Holen/Setzen von private y private static Variablen sowie den Aufruf von private y private static Methoden. Mit den folgenden Mustern können Sie so ziemlich alles tun, was mit den privaten Methoden und Feldern zu tun hat. Natürlich können Sie nicht ändern private static final Variablen durch Reflexion.

Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Und für Felder:

Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

注意事項
1. TargetClass.getDeclaredMethod(methodName, argClasses) ermöglicht Ihnen einen Blick in private Methoden. Das Gleiche gilt für getDeclaredField .
2. Die setAccessible(true) ist erforderlich, um mit Privaten herumzuspielen.

421 Stimmen

Nützlich, wenn Sie die API vielleicht nicht kennen, aber wenn Sie private Methoden auf diese Weise testen müssen, stimmt etwas mit Ihrem Design nicht. Wie ein anderer Poster sagt, sollten Unit-Tests den Vertrag der Klasse testen: Wenn der Vertrag zu weit gefasst ist und zu viel vom System instanziiert, sollte das Design überarbeitet werden.

14 Stimmen

Wir entwickeln Methoden, die eine einzige spezifische Aufgabe erfüllen, damit die Klasse ihre spezifische Aufgabe erfüllen kann. Diese Methoden sollten nicht öffentlich sein und müssen trotzdem unabhängig getestet werden. Ja, Reflection ist eine gute Möglichkeit, dies zu tun, und nein, Ihr Entwurf muss nicht überprüft werden, wenn Sie Reflection für diesen Zweck verwenden.

832voto

Der beste Weg, eine private Methode zu testen, ist eine andere öffentliche Methode. Wenn dies nicht möglich ist, dann ist eine der folgenden Bedingungen erfüllt:

  1. Die private Methode ist toter Code
  2. In der Nähe der Klasse, die Sie testen, gibt es einen Designgeruch
  3. Die Methode, die Sie testen wollen, sollte nicht privat sein

18 Stimmen

Außerdem erreichen wir ohnehin nie eine 100%ige Codeabdeckung. Konzentrieren Sie sich also bei den Qualitätstests auf die Methoden, die die Kunden tatsächlich direkt verwenden werden.

66 Stimmen

@grinch Genau richtig. Das einzige, was Sie durch das Testen privater Methoden gewinnen würden, sind Informationen zur Fehlersuche, und dafür sind Debugger da. Wenn Ihre Tests den Vertrag der Klasse vollständig abdecken, haben Sie alle Informationen, die Sie brauchen. Private Methoden sind ein Umsetzung Detail. Wenn Sie sie testen, müssen Sie Ihre Tests jedes Mal ändern, wenn sich Ihre Implementierung ändert, auch wenn sich der Vertrag nicht ändert. Im gesamten Lebenszyklus der Software wird dies wahrscheinlich viel mehr kosten als der Nutzen, den es bringt.

24 Stimmen

Ich bin beeindruckt, wie oft die Behauptung "sollte nicht privat sein" in den Antworten hier wiederholt wird, als ob "mach es öffentlich, damit du es testen kannst" nicht leicht zu Code-Geruch führen könnte, der andere einlädt, Teile einer Klasse zu missbrauchen. Sinnvolle Interna offenzulegen, nur um verschiedene Codepfade leichter testen zu können, ist nicht immer sinnvoll, also folgen Sie dieser Devise hier nicht blind!

386voto

Jay Bazuzi Punkte 43111

Wenn ich private Methoden in einer Klasse habe, die so kompliziert sind, dass ich das Bedürfnis habe, die privaten Methoden direkt zu testen, ist das ein Codegeruch: Meine Klasse ist zu kompliziert.

Mein üblicher Ansatz zur Lösung solcher Probleme besteht darin, eine neue Klasse zu entwickeln, die die interessanten Teile enthält. Oft können diese Methode und die Felder, mit denen sie interagiert, und vielleicht eine oder zwei weitere Methoden in eine neue Klasse extrahiert werden.

Die neue Klasse stellt diese Methoden als "öffentlich" dar, damit sie für Unit-Tests zugänglich sind. Die neue und die alte Klasse sind nun beide einfacher als die ursprüngliche Klasse, was für mich großartig ist (ich muss die Dinge einfach halten, sonst verliere ich den Überblick!)

Damit will ich nicht sagen, dass man Klassen erstellen soll, ohne sein Gehirn zu benutzen! Es geht hier darum, die Kräfte der Unit-Tests zu nutzen, um gute neue Klassen zu finden.

0 Stimmen

Warum eine neue Klasse erstellen, wenn Sie Ihre Methode ohnehin öffentlich machen können?

1 Stimmen

Wenn Sie in einer Klasse eine Mischung aus privaten und öffentlichen Methoden haben, ist das ein Hinweis darauf, dass es mehrere Verantwortlichkeiten gibt.

0 Stimmen

Verwenden Sie Reflection, um auf die private Methode in einem Test zuzugreifen. Ich habe zum Beispiel eine Implementierung eines Algorithmus in einer privaten Methode und diese Methode wird in einer anderen öffentlichen Methode verwendet. Ich muss also diesen Algorithmus ordnungsgemäß testen (sogar während ich diesen Algorithmus schreibe). Warum muss ich also einen Hack in den produktiven Code machen, nur um diese Methode testen zu können? Ja, die Verwendung von Java Reflection ist auch ein Hack, aber nur für den Test. Und wenn ich mich entscheide, die Methode (aus irgendeinem anderen Grund) in eine Utility-Klasse zu verschieben, kann ich den Test einfach mit verschieben fertig. Easy peasy, lesbar, wartbar.

343voto

Jon Punkte 3430

Ich habe verwendet Reflexion Ich habe in der Vergangenheit versucht, dies für Java zu tun, und meiner Meinung nach war das ein großer Fehler.

Streng genommen sollten Sie no Unit-Tests schreiben, die private Methoden direkt testen. Was Sie sollte Bei den Tests, die Sie durchführen, geht es um den öffentlichen Vertrag, den die Klasse mit anderen Objekten hat; Sie sollten niemals direkt die Interna eines Objekts testen. Wenn ein anderer Entwickler eine kleine interne Änderung an der Klasse vornehmen möchte, die sich nicht auf den öffentlichen Vertrag der Klasse auswirkt, muss er/sie Ihren reflektionsbasierten Test ändern, um sicherzustellen, dass er funktioniert. Wenn Sie dies im Laufe eines Projekts immer wieder tun, sind Unit-Tests kein nützlicher Gradmesser mehr für den Zustand des Codes, sondern werden zu einem Hindernis für die Entwicklung und zu einem Ärgernis für das Entwicklungsteam.

Ich empfehle stattdessen die Verwendung eines Codeabdeckungstools wie Cobertura, um sicherzustellen, dass die von Ihnen geschriebenen Unit-Tests eine angemessene Abdeckung des Codes in privaten Methoden bieten. Auf diese Weise testen Sie indirekt, was die privaten Methoden tun, und erhalten ein höheres Maß an Agilität.

85 Stimmen

+1 dazu. Meiner Meinung nach ist das die beste Antwort auf diese Frage. Wenn Sie private Methoden testen, testen Sie die Implementierung. Damit wird der Zweck von Unit-Tests verfehlt, der darin besteht, die Inputs/Outputs des Vertrags einer Klasse zu testen. Ein Test sollte nur genug über die Implementierung wissen, um die Methoden, die es in seinen Abhängigkeiten aufruft, nachzubilden. Mehr nicht. Wenn Sie Ihre Implementierung nicht ändern können, ohne einen Test ändern zu müssen, ist Ihre Teststrategie wahrscheinlich schlecht.

14 Stimmen

@Colin M Das ist aber nicht wirklich seine Frage ;) Lass ihn das entscheiden, du kennst das Projekt nicht.

6 Stimmen

Das stimmt nicht ganz. Es könnte sehr aufwendig sein, einen kleinen Teil der privaten Methode durch die öffentliche Methode zu testen, die sie verwendet. Die öffentliche Methode könnte eine umfangreiche Einrichtung erfordern, bevor Sie die Zeile erreichen, die Ihre private Methode aufruft

242voto

Iker Jimenez Punkte 6827

Aus diesem Artikel: Private Methoden mit JUnit und SuiteRunner testen (Bill Venners), haben Sie im Grunde 4 Möglichkeiten:

  1. Testen Sie keine privaten Methoden.
  2. Geben Sie den Methoden Paketzugang.
  3. Verwenden Sie eine verschachtelte Testklasse.
  4. Reflexion verwenden.

0 Stimmen

@JimmyT., Es kommt darauf an, für wen der "Produktionscode" bestimmt ist. Ich würde Code, der für Anwendungen innerhalb von VPN produziert wird, deren Zielbenutzer Sysadmins sind, als Produktionscode bezeichnen.

0 Stimmen

@Pacerier Was meinen Sie?

3 Stimmen

Die fünfte Option ist, wie oben erwähnt, das Testen der öffentlichen Methode, die die private Methode aufruft. Korrekt?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X