Есть некий класс, и работа его публичных методов основана на работе закрытых вспомогательных методов. Ну пусть такой:
public class PersonDate
{
public PersonDate(Date birthday) { ... }
public int getYearsOld()
{
return isValid() ? getYear( getNextBirthdayDate() ) - getYear( getBornDate() ) + 1 : 0;
}
// (TODO: нужен тест) возвращает год для даты
private static int getYear( Date date ) { ... }
// (TODO: нужен тест) возвращает дату следующего дня рождения
private Date getNextBirthdayDate() { ... }
Нужно убедиться, что закрытые вспомогательные функции getYear() и getNextBirthdayDate() правильно отрабатывают. Собственно, как протестировать их работу в JUnit или любом другом подобном фреймворке ?
Можно, конечно, сказать, что модульное тестирование (по фен-шую) не предполагает знание о внутреннем устройстве тестируемого класса, и органичиться тестированием только внешних методов (рассматривая класс чисто как черный ящик). Однако оставим в стороне "идеологические войны" и сконцентрируемся на поставленной задаче. Я вижу следующие способы решения вопроса.
1. Способ первый.
Метод getYear() объявлен статическим. Его можно вынести в публичный вспомогательный класс, либо внутренний, либо внешний:
static final class DateUtils
{
public static int getYear( Date date ) { ... }
}
и написать тест уже на новый класс. В данном случае это поможет. Мало того, согласно правилам хорошего кода - вынесение логики, не требующей данных класса, в изолированную функцию, даже правильно. Но что делать, когда подобный метод не является статичным и его работа базируется на значении внутренних полей класса?
2. Способ второй.
Объявить тестируемый метод с уровнем доступа package. Это сработает, т.к. тестирующий класс компилируется с тестируемым в одном и том же пакете. Но изменять область видимости только ради написания теста... хм...
3. Способ третий. Давно забытое старое.
Написать тестирующий класс внутри тестируемого:
public class PersonDate
{
...
public static class PersonDateTest
{
@Test
public testGetNextBirthDate()
{
}
}
В этом случае тестирующий класс получает полный доступ ко всем закрытым полям объекта-владельца.
Но вроде как, подобный подход - уже не по мейнстриму? Кажется ранее (до JUnit и подобных фреймворков), именно такая методика написания тестов и была основной. Внутренние тестовые классы при компиляции превращаются в отдельные файлы вида PersonDate$PersonDateTest.class и затем легко могут быть удалены из продакшн средствами сборки.
Коллеги, может быть кто знает другие более красивые способы?
Или какие-то фреймворки предоставляют подобный функционал?
Буду благодарен за все ваши ответы.