Java Tech Lead в Edvantis
  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    Спробувати можна. Наприклад ви побачили якийсь дуже складний приватний метод, але аж раптом — він зовнішні залежності не викликає — це вже один кандидат. Або можна спробувати спочатку зробити виклики зовнішніх сервісів, а потім вже пробувати обробити всі результати разом. Можна взагалі зробити Lazy запит — тобто обгорнути його у функцію і викликати його лиш тоді, коли треба. В імперативному програмуванні воно виглядає неорганічно, але от наприклад в WebFlux це — звична річ — передати якийсь Mono у функцію. Відповідно цей Mono може і не викликатися, а протестувати метод можна без моків, бо замість справжнього моно можна передати Mono.just().
    Я не кажу, що це завжди вийде, але якщо пробувати побачити такі місця, то їх виявляється більше, ніж спочатку очікувалося.

  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    Все вірно. Є трейдофи, головне знати про різні варіанти.

  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    Не обов’язково. Якщо винести бізнес-логіку в окремі компоненти, то їх можна тестувати без моків.
    Тобто ви, звісно, можете написати пару тестів з моками. Але при цьому тестувати компоненту, котра не має зовнішніх залежностей значно простіше.

  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    А чим спрінг завинив? Якщо ви конкретно про Dependency Injection — то він дуже спрощує роботу з ініціалізацією проекту. Тобто це просто інструмент, щоб руками об’єкти в конструктори передавати.
    Якщо відповідати на питання — виносите бізнес логіку в окремі компоненти і тестуєте їх без моків.

  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    Це цікава ідея. Але ні — інтерв’ювер хотів почути про «мок» про що сам мені зізнався. Я не думаю, що він би від мене це приховував.

  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    Якщо контролери-сервіси-даошки мають однорядочкові методи, котрі просто викликають одне одного і перетягують дані з бази на UI — тоді так, змісту з юніт-тестів небагато. Але щойно з’являється щось складніше — хоча б якась бізнес логіка (перевірка на консистентність переданих даних, якась особлива фільтрація чи сортування, перемаплення не 1-в-1 а щось поскладніше) — то вже можна юніт-тестувати. При чому по можливості треба переносити цю бізнес-логіку в окремі компоненти, котрі не мають зовнішніх залежностей і приклад цього поданий в статті (там де тестується OrderStatisticsNotificator).

    Підтримали: Gremlin, Volodymyr Metlyakov, Serhii
  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    Ключова фіча моків — це можливість перевірки взаємодії/інтеракції з об’єктом.

    Так, але, на жаль, часто моки використовують там, де їх використовувати не треба. Цитуючи вас же ж:

    Просте правило: ми мокаємо залежності юніта, який ми тестуємо. Тут складність визначити границі того юніта і що є залежністю, а що деталлю реалізації.

    і ось тут часто виникають проблеми, тому що мокають взагалі все, окрім лише класу, котрий тестують. Тобто мокають усі залежності — навіть якщо їх можна просто інстанціювати, мокають статичні методи, і навіть з моків вертають не ДТОшки, а моки ДТОшок, в котрих мокають гетери. І все через нерозуміння того, що мокати треба, а що ні. І в таких тестах можна забрати більшість моків і тест від цього стане лише кращим.

  • Мок — не чудодійний засіб, а необхідне зло. Переосмислюємо Unit-тестування

    Уникати тоді, коли цей ретурн неочевидний. Наприклад коли метод на 40 рядочків, а тут неждано-негадано ретурн на 23му.

    Підтримав: Mohican
  • Звідки в Java береться магія, або Що таке SPI

    Не зовсім так. «Перше, що знайду — те і буду використовувати» — це лише один зі способів вибору компонента. Чи робити саме так — залежить від фреймворку і потреб.
    Наприклад так можна робити, коли шукається проганяч тестів (test runner) для JUnit5. Ніхто ж не очікує, що при двох наявних реалізаціях в classpath, тести проганятимуться теж двічі. Але в тому ж випадку можна викинути помилку — логіка вибору компоненту самим SPI не задається, і JUnit5 міг би відмовитися проганяти тести при наявних двох реалізаціях (я, чесно, не перевіряв, що він зробить).
    Інтерфейс, який шукають, може оголосити метод .priority(). І тоді після того, як завантажаться всі реалізації, можна посортувати по пріорітету і взяти з найвищим.
    Мало того, можна обрати декілька імплементацій. Саме так відбувається з javax.servlet.ServletContainerInitializer — саме тому в одному контейнері сервлетів може існувати паралельно і SpringMVC і Jersey — обоє оголошують реалізацію javax.servlet.ServletContainerInitializer і контейнер сервлетів ініціалізує обидва.
    Але зазвичай ми самі рідко контролюємо логіку підбору компонентів, адже фреймворки ми пишемо рідко. І відповідно ми залежимо від того, як SPI реалізували самі фреймворки. Те, що вони роблять, і справді часто виглядає, як магія — тут я погоджуюся.

  • Топ-10 рис програміста-професіонала. Огляд книги Clean Coder Роберта Мартіна

    В Кента Бека досить адекватне бачення TDD, до речі. Ось цитата з його інтерв’ю:
    “If you’re in exploration mode and you’re just trying to figure out what a program might do and most of your experiments are going to be failures and be deleted in a matter of hours or perhaps days, then most of the benefits of TDD don’t kick in, and it slows down the experimentation”

  • Звідки в Java береться магія, або Що таке SPI

    Залежить від того, хто шукає драйвер. По-перше драйвер можна взагалі не шукати, просто беремо потрібний драйвер, ініціалізуємо його за допомогою new і працюємо надалі з ним.
    Далі все залежить від фреймворка. Наприклад є фреймворки, де правильний драйвер задається прямо в конфігураційних файлах — наприклад Hibernate дійсно може шукати назву драйвера в якісь xml-ці. Я впевнений, що драйвер може бути заданий і в property файлі, чи environment variable.
    Але якщо драйвер явно не вказується, тоді пошук може відбуватися (і часто таки відбувається) за допомогою SPI. Тобто вантажаться усі класи, вказані в усіх ресурсах під іменем

    META-INF/services/java.sql.Driver
    .
    Далі, використовуючи метод
    driver.acceptsUrl

    обираєтсья той драйвер, котрий вміє працювати з даною базою (адже в кожної бази урла інша).
    Щодо замовчувань — то замовчувань немає. Якщо жоден драйвер не підтримує задану урлу до бази, то ніякий драйвер і не повернеться і, швидше всього, ви отримаєте повідомлення про помилку.
    Підтримав: Denys
  • Звідки в Java береться магія, або Що таке SPI

    Для того, щоб спитати в ChatGPT «Що таке SPI в Java?» для початку треба знати, що SPI в джаві взагалі існує.

  • Звідки в Java береться магія, або Що таке SPI

    Зараз існує GraalVM, там теж є AOT (Ahead of Time) компілятор, що компілює безпосередньо в машинний код.

  • Звідки в Java береться магія, або Що таке SPI

    Чесно, випадково вийшло. Як справжнього джавіста мене мало цікавлять низькорівневі інтерфейси, тому була відустня стійка асоціація абревіатури SPI з чимось окрім як джавішної технології.