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.
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.
Beim Testen von Legacy-Code mit großen und eigenwilligen Klassen ist es oft sehr hilfreich, die eine private (oder öffentliche) Methode, die ich schreibe, testen zu können im Augenblick .
Ich benutze die junitx.util.PrivateAccessor -Paket für Java . Viele hilfreiche Einzeiler für den Zugriff auf private Methoden und private Felder.
import junitx.util.PrivateAccessor;
PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);
Stellen Sie sicher, dass Sie die gesamten JUnit-Addons ( sourceforge.net/projects/junit-addons ) Paket, nicht das von der Source Forge empfohlene Projekt PrivateAccessor.
Nach dem Ausprobieren von Cem Catikkas' Lösung durch Reflexion für Java, muss ich sagen, dass seine Lösung eleganter war, als ich sie hier beschrieben habe. Wenn Sie jedoch nach einer Alternative zur Verwendung von Reflection suchen und Zugriff auf den Quellcode haben, den Sie testen, ist dies immer noch eine Option.
Es kann sinnvoll sein, private Methoden einer Klasse zu testen, insbesondere bei testgetriebene Entwicklung Sie möchten kleine Tests entwerfen, bevor Sie einen Code schreiben.
Wenn Sie einen Test mit Zugriff auf private Mitglieder und Methoden erstellen, können Sie Bereiche des Codes testen, die nur mit Zugriff auf öffentliche Methoden schwer zu erfassen sind. Wenn eine öffentliche Methode mehrere Schritte umfasst, kann sie aus mehreren privaten Methoden bestehen, die dann einzeln getestet werden können.
Vorteile:
Benachteiligungen:
Wenn jedoch kontinuierliche Tests diese Methode erfordern, kann dies ein Zeichen dafür sein, dass die privaten Methoden extrahiert werden sollten, die auf herkömmliche, öffentliche Weise getestet werden könnten.
Hier ein kompliziertes Beispiel, wie das funktionieren könnte:
// Import statements and package declarations
public class ClassToTest
{
private int decrement(int toDecrement) {
toDecrement--;
return toDecrement;
}
// Constructor and the rest of the class
public static class StaticInnerTest extends TestCase
{
public StaticInnerTest(){
super();
}
public void testDecrement(){
int number = 10;
ClassToTest toTest= new ClassToTest();
int decremented = toTest.decrement(number);
assertEquals(9, decremented);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(StaticInnerTest.class);
}
}
}
Die innere Klasse würde kompiliert werden zu ClassToTest$StaticInnerTest
.
Siehe auch: Java-Tipp 106: Statische innere Klassen für Spaß und Gewinn
Bei Verwendung von Spring, ReflectionTestUtils bietet einige praktische Tools, die hier mit minimalem Aufwand weiterhelfen. Zum Beispiel, um ein Mock auf ein privates Mitglied einzurichten, ohne gezwungen zu sein, einen unerwünschten öffentlichen Setter hinzuzufügen:
ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);
Wie andere schon sagten: Testen Sie private Methoden nicht direkt. Hier sind ein paar Gedanken:
Führen Sie die Codeabdeckung für die Unit-Tests durch. Wenn Sie sehen, dass Methoden nicht vollständig getestet werden, fügen Sie den Tests etwas hinzu, um die Abdeckung zu erhöhen. Streben Sie eine Codeabdeckung von 100 % an, aber seien Sie sich bewusst, dass Sie das wahrscheinlich nicht erreichen werden.
Auf zur Codeabdeckung. Egal, welche Art von Logik sich in der privaten Methode befindet, Sie rufen diese Logik immer noch über eine öffentliche Methode auf. Ein Tool zur Codeabdeckung kann Ihnen zeigen, welche Teile durch den Test abgedeckt sind, so dass Sie sehen können, ob Ihre private Methode getestet wird.
Private Methoden werden von öffentlichen Methoden konsumiert. Sonst sind sie toter Code. Deshalb testen Sie die öffentliche Methode, indem Sie die erwarteten Ergebnisse der öffentlichen Methode und damit der privaten Methoden, die sie verbraucht, überprüfen.
Das Testen privater Methoden sollte durch Debugging getestet werden, bevor Sie Ihre Unit-Tests für öffentliche Methoden ausführen.
Sie können auch mit Hilfe von testgetriebener Entwicklung debuggt werden, indem Sie Ihre Unit-Tests debuggen, bis alle Behauptungen erfüllt sind.
Ich persönlich glaube, dass es besser ist, Klassen mit TDD zu erstellen; Erstellen der öffentlichen Methode Stubs, dann erzeugen Unit-Tests mit alle die Behauptungen im Voraus definiert, so dass das erwartete Ergebnis der Methode feststeht, bevor Sie sie codieren. Auf diese Weise gehen Sie nicht den falschen Weg, indem Sie die Behauptungen der Einheitstests an die Ergebnisse anpassen. Ihre Klasse ist dann robust und erfüllt die Anforderungen, wenn alle Unit-Tests erfolgreich sind.
Dies ist zwar richtig, kann aber zu sehr komplizierten Tests führen - es ist besser, jeweils eine einzelne Methode zu testen (Unit-Testing), als eine ganze Gruppe von Methoden. Das ist kein schlechter Vorschlag, aber ich denke, es gibt hier bessere Lösungen - dies sollte der letzte Ausweg sein.
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.
327 Stimmen
Der beste Weg, eine private Methode zu testen, ist, sie nicht direkt zu testen
30 Stimmen
Lesen Sie den Artikel Testen privater Methoden mit JUnit und SuiteRunner .
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.
7 Stimmen
Ich habe diese Frage in ihren ursprünglichen Zustand zurückversetzt, bevor ich die Frage generiert habe. In ihrem jetzigen Zustand sind die Antworten sehr Java-orientiert, und die Frage konzentrierte sich weitgehend auf das "Wie", was bedeutet, dass die späteren Versionen, die Java auslöschen und für andere Sprachen verallgemeinern, und am Ende den Fokus auf C++ verlagern, viel zu viele der Antworten ungültig machen. Eine verallgemeinerte Form, die nach dem "Wie" in einer beliebigen Sprache und einem beliebigen Framework fragt, würde ebenfalls als viel zu weit gefasst angesehen werden, was bedeutet, dass die letzten Bearbeitungen diese Frage eher in Richtung Schließung als in Richtung Konstruktivität getrieben haben.
8 Stimmen
@AkashVerma: Aus demselben Grund, aus dem Sie Unit-Tests statt nur Systemtests durchführen wollen?
0 Stimmen
Siehe auch: stackoverflow.com/questions/250692/ . Die zugrunde liegende philosophische Frage ist sprachunabhängig.
0 Stimmen
Siehe: github.com/ljr1981/stack_overflow_answers/blob/main/src/ y github.com/ljr1981/stack_overflow_answers/blob/main/testing/
0 Stimmen
Im vorherigen Kommentar zeige ich Ihnen, wie einfach das in Eiffel ist. In diesem Fall habe ich eine Klasse namens SO_34571 mit einem Methoden-Feature namens `my_private_method' erstellt. Beachten Sie, dass auf das Gruppenschlüsselwort "feature" ein {TEST_SET_BRIDGE} folgt. Das bedeutet, dass jede Klasse, die von TEST_SET_BRIDGE erbt (einschließlich ihrer Nachkommen), die Erlaubnis hat, auf jedes Feature der Feature-Gruppe zuzugreifen. Sauber. Einfach. Elegant. Skalierbar. Kontrollierbar. Schön!