Добрый день! Статья будет про один совершенно незначительный момент в кодировании.
Например, многие мои коллеги сказали – Doch, das ist ganz normal! “А, чё, все норм, нашел к чему придраться!” Но, тем не менее.

Есть несколько вещей в написании кода которые меня бесят. Ну, на самом деле не несколько. :), чем старше становлюсь, тем больше и больше таких вещей, характер не лучшает. Но в топе – когда девелоперы пишут тесты к private методам. А, нет! Когда они ради этого убирают слово private у метода и метод становится package-private.

Вот, ты такой ревьювишь класс, строк этак на 3К, написанный в лучших традициях процедурного программирования, а там 10 методов public, 10 private, а еще 15 package-private. И про интерфейсы мы не слышали – это ж сервис, давай так прям так и инжектить! Ок, думаешь ты, сейчас рукава засучим, вынесем все public методы в интерфейс, helper-ы, их в отдельный package – короче распилим это безумство на части согласно SRP. Но тут же обнаруживаешь, что package-private методы давно дергаются из других мест. Дык у нас все классы в один package свалены! If something can be misused, it will be misused for sure, как говорится.

Да-да, все знают, писать тесты к private методам не надо, если ты это делаешь, то что-то не так с дизайном, и так далее. Но, блин, люди все равно это делают, и надо сказать, не без причин. Представте, что упомянутый выше класс вообще был с zero test coverage. А рефакторить надо. Вот так и появляются package-private методы. Но как же нам быть – вон и Whitebox из Mockito выпилили, конечно в PowerMock он остался, но ради этого тащить PowerMock в проект, да и синтаксис не лучше прямого вызова через reflection. Можно конечно свой велосипед написать, но… И так и так не айс получается.

А вот представьте, что для доступа к private элементам класса – методам, полям, у нас есть интерфейс. Что за фигня, вы скажете, совсем парень заработался. А вот так:

Есть класс:

public class ObjectWithPrivates {
    private final AtomicInteger count = new AtomicInteger(0);
    private String name;

    private String methodToTest(String in) {
        return name + in + count.incrementAndGet();
    }
}

Тест:

interface TestPrivates {
    void setName(String name);
    String methodToTest(String in);
    AtomicInteger getCount();
}

@Test
void testPrivates() {
    ObjectWithPrivates obj = new ObjectWithPrivates();
    TestPrivates objWithPrivates = API.lookupPrivatesIn(obj)
                                      .usingInterface(TestPrivates.class);

    objWithPrivates.setName("Andromeda");
    String in = objWithPrivates.methodToTest("in");
    AtomicInteger count = objWithPrivates.getCount();

    Assertions.assertEquals("Andromedain1", in);
    Assertions.assertEquals(1, count.get());
}

Как видите, с помощью интерфейса мы можем дергать private методы, и получать доступ к private полям. Ну и по коду сразу можно сказать, что происходит. Имейте ввиду, что все манипуляции происходят с obj и можно, например, засетить все private поля у obj и потом дернуть public метод.

Можно получить доступ к private полям/методам родительского класса:

TestPrivates accessToPrivates = API.lookupPrivatesIn(obj)
                                   .lookupInSuperclass()
                                   .usingInterface(TestPrivates.class);

А можно и статические методы дергать:

TestPrivates accessToPrivates = lookupPrivatesIn(SomePOJOClass.class)
                                .usingInterface(TestPrivates.class);
accessToPrivate.someStaticPrivateMethod();

А можно и объект создать через private конструктор.

Под капотом там стандартный reflection и Dynamic Proxy, никаких дополнительных зависимостей.

Вот ссылка на проект testprivates. Использовать только для тестов.

Всех с наступающим, не болейте!

Let’s block ads! (Why?)

Read More

Recent Posts

Роскомнадзор рекомендовал хостинг-провайдерам ограничить сбор данных с сайтов для иностранных ботов

Центр управления связью общего пользования (ЦМУ ССОП) Роскомнадзора рекомендовал компаниям из реестра провайдеров ограничить доступ поисковых ботов к информации на российских сайтах.…

19 часов ago

Apple возобновила переговоры с OpenAI и Google для интеграции ИИ в iPhone

Apple возобновила переговоры с OpenAI о возможности внедрения ИИ-технологий в iOS 18, на основе данной операционной системы будут работать новые…

6 дней ago

Российская «дочка» Google подготовила 23 иска к крупнейшим игрокам рекламного рынка

Конкурсный управляющий российской «дочки» Google подготовил 23 иска к участникам рекламного рынка. Общая сумма исков составляет 16 млрд рублей –…

6 дней ago

Google завершил обновление основного алгоритма March 2024 Core Update

Google завершил обновление основного алгоритма March 2024 Core Update. Раскатка обновлений была завершена 19 апреля, но сообщил об этом поисковик…

6 дней ago

Нейросети будут писать тексты объявления за продавцов на Авито

У частных продавцов на Авито появилась возможность составлять текст объявлений с помощью нейросети. Новый функционал доступен в категории «Обувь, одежда,…

6 дней ago

Объявлены победители международной премии Workspace Digital Awards-2024

24 апреля 2024 года в Москве состоялась церемония вручения наград международного конкурса Workspace Digital Awards. В этом году участниками стали…

7 дней ago