Frage Wie prüfe ich eine private Funktion oder eine Klasse mit privaten Methoden, Feldern oder inneren Klassen?


Wie teste ich (mit xUnit) eine Klasse mit internen privaten Methoden, Feldern oder verschachtelten Klassen? Oder eine Funktion, die privat gemacht wird interne Verknüpfung (static in C / C ++) oder in einem privaten (anonym) Namensraum?

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


2265


Ursprung


Antworten:


Wenn Sie etwas von einem Vermächtnis haben Java Anwendung, und Sie dürfen nicht die Sichtbarkeit Ihrer Methoden ändern, ist der beste Weg, um private Methoden zu testen Betrachtung.

Intern verwenden wir Helfer zum Abrufen / Einstellen private und private static Variablen sowie aufrufen private und 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);

Anmerkungen:
  1. targetClass.getDeclaredMethod(methodName, argClasses) lässt dich hineinsehen private Methoden. Das Gleiche gilt für    getDeclaredField.
  2. Die setAccessible(true) ist erforderlich, um mit Privatpersonen herumzuspielen.


1416



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

  1. Die private Methode ist ein toter Code
  2. Es gibt einen Design-Geruch in der Nähe der Klasse, die Sie testen
  3. Die Methode, die Sie testen möchten, sollte nicht privat sein

506



Wenn ich private Methoden in einer Klasse habe, die so kompliziert sind, dass ich die Notwendigkeit verspüre, die privaten Methoden direkt zu testen, dann ist das ein Code-Geruch: Meine Klasse ist zu kompliziert.

Mein üblicher Ansatz, um solche Probleme anzugehen, besteht darin, eine neue Klasse hervorzubringen, die die interessanten Bits enthält. Häufig können diese Methode und die Felder, mit denen sie interagiert, und möglicherweise eine oder zwei andere Methoden in eine neue Klasse extrahiert werden.

Die neue Klasse macht diese Methoden als "öffentlich" verfügbar, sodass sie für Komponententests zugänglich sind. Die neuen und alten Klassen sind jetzt beide einfacher als die ursprüngliche Klasse, was für mich großartig ist (ich muss die Dinge einfach halten oder ich verliere mich!).

Beachten Sie, dass ich nicht vorschlage, dass Leute Klassen erstellen, ohne ihr Gehirn zu benutzen! Der Punkt hier ist, die Kräfte des Komponententests zu verwenden, um Ihnen zu helfen, gute neue Klassen zu finden.


271



Ich habe benutzt Betrachtung Dies in der Vergangenheit für Java zu tun, und meiner Meinung nach war es ein großer Fehler.

Genau genommen sollten Sie das tun nicht Schreiben von Komponententests, die direkt private Methoden testen. Was du sollte Testen ist der öffentliche Vertrag, den die Klasse mit anderen Objekten hat; Sie sollten die Interna eines Objekts niemals direkt testen. Wenn ein anderer Entwickler eine kleine interne Änderung an der Klasse vornehmen möchte, die sich nicht auf den öffentlichen Vertrag der Klassen auswirkt, muss er / sie dann Ihren reflexionsbasierten Test ändern, um sicherzustellen, dass er funktioniert. Wenn Sie dies wiederholt während eines Projekts tun, hören die Komponententests auf, ein nützliches Maß für die Code-Gesundheit zu sein, und werden ein Entwicklungshindernis und ein Ärgernis für das Entwicklungsteam.

Stattdessen empfehle ich die Verwendung eines Code-Coverage-Tools wie Cobertura, um sicherzustellen, dass die Unit-Tests, die Sie schreiben, eine angemessene Abdeckung des Codes in privaten Methoden bereitstellen. Auf diese Weise können Sie indirekt testen, was die privaten Methoden tun, und eine höhere Agilität beibehalten.


229



Aus diesem Artikel: Testen von privaten Methoden mit JUnit und SuiteRunner (Bill Venners), Sie haben grundsätzlich 4 Möglichkeiten:

  • Testen Sie keine privaten Methoden.
  • Geben Sie dem Methodenpaket Zugriff.
  • Verwenden Sie eine geschachtelte Testklasse.
  • Verwenden Sie Reflexion.

187



Im Allgemeinen ist ein Komponententest dazu gedacht, die öffentliche Schnittstelle einer Klasse oder Einheit auszuüben. Daher sind private Methoden Implementierungsdetails, die Sie nicht explizit testen würden.


96



Nur zwei Beispiele, wo ich eine private Methode testen möchte:

  1. Entschlüsselungsroutinen - Ich würde nicht Ich möchte sie für jeden sichtbar machen, nur um ihn zu sehen um des Testens willen, sonst kann jeder benutze sie zum Entschlüsseln. Aber sie sind intrinsisch für den Code, kompliziert, und müssen immer funktionieren (die offensichtliche Ausnahme ist die Reflektion, die verwendet werden kann, um selbst private Methoden in den meisten Fällen zu sehen, wann SecurityManager ist nicht konfiguriert, dies zu verhindern).
  2. Erstellen eines SDK für die Gemeinschaft Verbrauch. Hier nimmt die Öffentlichkeit eine ganz andere Bedeutung, seit diesem ist ein Code, den die ganze Welt sehen kann (nicht nur intern zu meiner Bewerbung). Ich legte Code in private Methoden, wenn nicht möchte, dass die SDK-Benutzer es sehen - I sehe das nicht als Code-Geruch, bloß So funktioniert die SDK-Programmierung. Aber von Natürlich muss ich noch meine testen private Methoden, und sie sind wo die Funktionalität meines SDK tatsächlich Leben.

Ich verstehe die Idee, nur den "Vertrag" zu testen. Aber ich sehe nicht, dass man befürworten kann, Code nicht wirklich zu testen - Ihre Laufleistung kann variieren.

Mein Kompromiss besteht also darin, die JUnits durch Reflexion zu komplizieren, anstatt meine Sicherheit und das SDK zu kompromittieren.


56



Die privaten Methoden werden von einer öffentlichen Methode aufgerufen. Daher sollten die Eingaben für Ihre öffentlichen Methoden auch private Methoden testen, die von diesen öffentlichen Methoden aufgerufen werden. Wenn eine öffentliche Methode fehlschlägt, könnte dies ein Fehler in der privaten Methode sein.


53



Ein anderer Ansatz, den ich verwendet habe, ist, eine private Methode zu ändern, um privat oder geschützt zu verpacken, dann ergänze sie mit der @ VisibleForTesting Annotation der Google Guava-Bibliothek.

Dies wird jedem, der diese Methode verwendet, zeigen, Vorsicht walten zu lassen und auch in einem Paket nicht direkt darauf zuzugreifen. Auch eine Testklasse muss nicht im gleichen Paket sein physisch, aber im gleichen Paket unter der Prüfung Mappe.

Zum Beispiel, wenn eine zu testende Methode in ist src/main/java/mypackage/MyClass.java dann sollte dein Testanruf in platziert werden src/test/java/mypackage/MyClassTest.java. Auf diese Weise haben Sie Zugriff auf die Testmethode in Ihrer Testklasse.


29



Um älteren Code mit großen und skurrilen Klassen zu testen, ist es oft sehr hilfreich, die eine private (oder öffentliche) Methode, die ich schreibe, testen zu können jetzt sofort.

Ich verwende das junitx.util.PrivatAccessor-Paket für Java. Viele hilfreiche Einzeiler für den Zugriff auf private Methoden und private Bereiche.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);

28