Ich würde vorschlagen, dass Sie Ihren Code ein wenig umgestalten. Wenn Sie darüber nachdenken müssen, Reflektion oder andere Dinge zu verwenden, um nur Ihren Code zu testen, läuft etwas mit Ihrem Code nicht.
Sie haben verschiedene Arten von Problemen erwähnt. Beginnen wir mit privaten Feldern. Bei privaten Feldern hätte ich einen neuen Konstruktor hinzugefügt und Felder eingefügt. An Stelle von:
public class ClassToTest {
private final String first = "first";
private final List<String> second = new ArrayList<>();
...
}
Ich hätte das 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 auch mit altem Code kein Problem. Alter Code verwendet einen leeren Konstruktor, und wenn Sie mich fragen, sieht überarbeiteter Code sauberer aus, und Sie können die erforderlichen Werte ohne Reflexion in den Test einfügen.
Nun zu privaten Methoden. Nach meiner persönlichen Erfahrung hat diese Methode in dieser Klasse nichts zu tun, wenn Sie eine private Methode zum Testen stubben müssen. In diesem Fall besteht ein gängiges Muster darin, es in eine Schnittstelle zu verpacken , 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 wäre es ein Abhängigkeitsinjektionsmuster. Nach meiner persönlichen Erfahrung ist es beim Testen sehr nützlich, und ich denke, dass diese Art von Code sauberer und einfacher zu warten ist. Ich würde dasselbe über verschachtelte Klassen sagen. Wenn eine verschachtelte Klasse eine umfangreiche Logik enthält, ist es besser, wenn Sie sie als private Paketklasse verschoben und in eine Klasse eingefügt haben, die sie benötigt.
Es gibt auch einige andere Entwurfsmuster, die ich beim Umgestalten und Verwalten von Legacy-Code verwendet habe, aber alles hängt von den Fällen ab, in denen Ihr Code getestet werden soll. Die Verwendung von Reflection ist meistens kein Problem, aber wenn Sie eine Unternehmensanwendung haben, die stark getestet wird und Tests vor jeder Bereitstellung ausgeführt werden, wird alles sehr langsam (es ist nur ärgerlich und ich mag solche Dinge nicht).
Es gibt auch eine Setter-Injektion, aber ich würde nicht empfehlen, sie zu verwenden. Ich bleibe lieber bei einem Konstruktor und initialisiere alles, wenn es wirklich notwendig ist, und lasse die Möglichkeit, notwendige Abhängigkeiten einzufügen.