Я бы посоветовал вам немного изменить свой код. Когда вам нужно начать думать об использовании рефлексии или чего-то другого для простого тестирования кода, что-то идет не так с вашим кодом.
Вы упомянули разные типы проблем. Давайте начнем с частных полей. В случае приватных полей я бы добавил новый конструктор и вставил в него поля. Вместо этого:
public class ClassToTest {
private final String first = "first";
private final List<String> second = new ArrayList<>();
...
}
Я бы использовал это:
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;
}
...
}
Это не будет проблемой даже с некоторым устаревшим кодом. Старый код будет использовать пустой конструктор, и, если вы спросите меня, рефакторинговый код будет выглядеть чище, и вы сможете ввести необходимые значения в тест без отражения.
Теперь о частных методах. По моему личному опыту, когда вам нужно заглушить приватный метод для тестирования, тогда этот метод не имеет ничего общего с этим классом. В этом случае обычным шаблоном будет заключаться в том, чтобы обернуть его в интерфейсе, как, Callable
а затем передать этот интерфейс также в конструкторе (с помощью этого трюка с несколькими конструкторами):
public ClassToTest() {
this(...);
}
public ClassToTest(final Callable<T> privateMethodLogic) {
this.privateMethodLogic = privateMethodLogic;
}
В основном все, что я написал, выглядит как шаблон внедрения зависимостей. По моему личному опыту, это действительно полезно при тестировании, и я думаю, что этот вид кода чище и его будет легче поддерживать. Я бы сказал то же самое о вложенных классах. Если вложенный класс содержит тяжелую логику, было бы лучше, если бы вы переместили его как закрытый класс пакета и внедрили его в класс, который в этом нуждается.
Есть также несколько других шаблонов проектирования, которые я использовал при рефакторинге и обслуживании старого кода, но все зависит от случаев тестирования вашего кода. Использование рефлексии по большей части не является проблемой, но когда у вас есть корпоративное приложение, которое тщательно тестируется и тесты запускаются перед каждым развертыванием, все становится очень медленным (это просто раздражает, и мне не нравятся подобные вещи).
Существует также сеттерная инъекция, но я бы не рекомендовал ее использовать. Я лучше придерживаюсь конструктора и инициализирую все, когда это действительно необходимо, оставляя возможность для внедрения необходимых зависимостей.