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.
Wenn Sie JUnit verwenden, werfen Sie einen Blick auf junit-addons . Es hat die Fähigkeit, das Java-Sicherheitsmodell zu ignorieren und auf private Methoden und Attribute zuzugreifen.
Ich würde vorschlagen, dass Sie Ihren Code ein wenig umgestalten. Wenn Sie anfangen müssen, über die Verwendung von Reflexion oder andere Dinge nachzudenken, nur um Ihren Code zu testen, läuft etwas mit Ihrem Code schief.
Sie haben verschiedene Arten von Problemen erwähnt. Beginnen wir mit privaten Feldern. Im Falle von privaten Feldern hätte ich einen neuen Konstruktor hinzugefügt und Felder in diesen injiziert. Anstatt dessen:
public class ClassToTest {
private final String first = "first";
private final List<String> second = new ArrayList<>();
...
}
Ich hätte das hier benutzt:
public class ClassToTest {
private final String first;
private final List<String> second;
public ClassToTest() {
this("first", new ArrayList<>());
}
public ClassToTest(final String first, final List<String> second) {
this.first = first;
this.second = second;
}
...
}
Dies ist selbst bei altem Code kein Problem. Alter Code wird einen leeren Konstruktor verwenden, und wenn Sie mich fragen, wird der überarbeitete Code sauberer aussehen, und Sie werden in der Lage sein, notwendige Werte in Tests ohne Reflexion zu injizieren.
Nun zu den privaten Methoden. Meiner persönlichen Erfahrung nach hat eine private Methode, die man zum Testen stubben muss, in dieser Klasse nichts zu suchen. Ein übliches Muster wäre in diesem Fall, dass man wickeln innerhalb einer Schnittstelle, wie Callable
und dann übergeben Sie diese Schnittstelle auch im Konstruktor (mit diesem Trick mit mehreren Konstruktoren):
public ClassToTest() {
this(...);
}
public ClassToTest(final Callable<T> privateMethodLogic) {
this.privateMethodLogic = privateMethodLogic;
}
Meistens sieht alles, was ich geschrieben habe, so aus, als ob es sich um ein Dependency Injection Pattern handelt. Meiner persönlichen Erfahrung nach ist es beim Testen sehr nützlich, und ich denke, dass diese Art von Code sauberer ist und leichter zu pflegen ist. Dasselbe würde ich über verschachtelte Klassen sagen. Wenn eine verschachtelte Klasse schwere Logik enthält, wäre es besser, sie als private Klasse in ein Paket zu verschieben und sie in eine Klasse zu injizieren, die sie benötigt.
Es gibt auch einige andere Entwurfsmuster, die ich beim Refactoring und bei der Wartung von Legacy-Code verwendet habe, aber es hängt alles von den zu testenden Fällen Ihres Codes ab. Die Verwendung von Reflection ist meistens kein Problem, aber wenn man eine Unternehmensanwendung hat, die intensiv getestet wird und die Tests vor jedem Einsatz ausgeführt werden, wird alles sehr langsam (das ist einfach ärgerlich und ich mag so etwas nicht).
Es gibt auch Setter Injection, aber ich würde nicht empfehlen, sie zu verwenden. Ich würde besser mit einem Konstruktor bleiben und alles initialisieren, wenn es wirklich notwendig ist, so dass die Möglichkeit für die Injektion von notwendigen Abhängigkeiten.
Nicht einverstanden mit der ClassToTest(Callable)
Injektion. Das macht ClassToTest
komplizierter. Halten Sie es einfach. Auch das erfordert dann jemand anders zu erzählen ClassToTest
etwas, das ClassToTest
der Chef sein sollte. Es gibt einen Platz für das Einfügen von Logik, aber das ist er nicht. Sie haben die Klasse nicht einfacher, sondern schwieriger zu pflegen gemacht.
Außerdem ist es von Vorteil, wenn Ihre Testmethode X
erhöht nicht X
Komplexität bis zu dem Punkt, an dem sie mehr Probleme verursachen könnte... und daher zusätzliche Tests erfordert... was, wenn Sie auf eine Weise implementiert haben, die mehr Probleme verursachen kann... (dies ist keine Endlosschleife; jede Iteration ist wahrscheinlich kleiner als die vorherige, aber immer noch ärgerlich)
Könnten Sie erklären, warum es die Klasse ClassToTest
schwieriger zu pflegen? Eigentlich macht es Ihre Anwendung leichter zu pflegen, was schlagen Sie vor, eine neue Klasse für jeden verschiedenen Wert, den Sie in first
und 'zweite' Variablen?
Nachstehend finden Sie ein Beispiel;
Die folgende Importanweisung sollte hinzugefügt werden:
import org.powermock.reflect.Whitebox;
Jetzt können Sie das Objekt direkt übergeben, das die private Methode, den aufzurufenden Methodennamen und zusätzliche Parameter enthält (siehe unten).
Whitebox.invokeMethod(obj, "privateMethod", "param1");
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!