Please open Telegram to view this post
VIEW IN TELEGRAM
😁7
Привет!
Так, ну большая веха пройдена, расскажу про свои ближайшие планы.
И главный ближайший план - отдохнуть. До марта.
У меня с июля идёт жёсткий спринт, где я жонглирую домом с младенцем и старшим ребёнком, который за 3 месяца сходил в сад 7 дней, выступлением и проектом Р, где дикая жопа тянется с июня.
Но перед тем как начать уже отдыхать я планирую:
1. На следующей недели съездить на оффлайн часть конфы и сделать там лайтенинг толк с кратким пересказом изначального доклада про Spring Data JDBC
2. Допричёсывать и скинуть ссылки на демо проекты для доклада про SDJ
3.Выбрать и опубликовать тестовые прогоны всех трёх докладов: оригинальной полной версии доклада про SDJ, финального доклада про структурный дизайн и лайтенинг толка про SDJ
4. Протегать все свои посты и сделать "домшнюю страницу" со ссылками на тематические подборки
5. У меня есть предвfрительная договорённость зайти в гости к @javaswag - надеюсь там ещё лицом поторгую
На это всё, думаю, у меня уйдёт месяц-полтора.
А после отпуска я планирую несколько поменять подход к проработке ЭП - хочу завести сайт-вики и там для начала просто собрать и описать список всех паттернов и моделей, которые использую в своей работе.
Вот такие дела, стейтюнед, мы найдём способ делать системы так, чтобы работать было по кайфу:)
Так, ну большая веха пройдена, расскажу про свои ближайшие планы.
И главный ближайший план - отдохнуть. До марта.
У меня с июля идёт жёсткий спринт, где я жонглирую домом с младенцем и старшим ребёнком, который за 3 месяца сходил в сад 7 дней, выступлением и проектом Р, где дикая жопа тянется с июня.
Но перед тем как начать уже отдыхать я планирую:
3.
На это всё, думаю, у меня уйдёт месяц-полтора.
А после отпуска я планирую несколько поменять подход к проработке ЭП - хочу завести сайт-вики и там для начала просто собрать и описать список всех паттернов и моделей, которые использую в своей работе.
Вот такие дела, стейтюнед, мы найдём способ делать системы так, чтобы работать было по кайфу:)
Telegram
Эргономичный код
Привет!
Я как всегда облажался с оценкой оверхеда на сетап проекта и сроки по Проекту Р начали подгорать.
Поэтому на этой недели не расскажу, как поднимаю БД на 300+ таблиц, собираемых из 8 лет миграций меньше чем за пару секунд.
Но быстренько поделюсь…
Я как всегда облажался с оценкой оверхеда на сетап проекта и сроки по Проекту Р начали подгорать.
Поэтому на этой недели не расскажу, как поднимаю БД на 300+ таблиц, собираемых из 8 лет миграций меньше чем за пару секунд.
Но быстренько поделюсь…
❤16🔥5
Хейтеры такие хейтеры:)
Относительно прошлого выступления обратная связь неоднозначния.
Отзывов больше (27 вс 23) и лучше (4.4 вс 4.1). Но досмотрели доклад до конца сильно меньше (40% вс 74%). С просмотрами, возможно, разница в значительной степени обусловлена онлайном и оффлайном
Относительно прошлого выступления обратная связь неоднозначния.
Отзывов больше (27 вс 23) и лучше (4.4 вс 4.1). Но досмотрели доклад до конца сильно меньше (40% вс 74%). С просмотрами, возможно, разница в значительной степени обусловлена онлайном и оффлайном
👍3
Привет!
История ужасов про мутабельное состояние.
Есть у нас тут в Проекте Р задачка по загрзуке файла. Отдали её юниору. Он вчера провозился весь день - не осилил загрузить, спринг ругается что не видит multipart part.
Сегодня подключился я. Сделал мастер-класс по ТДД, докинул пару параметров, тест (поверх MockMvc) прошёл. На всякий случай (не верю я этим мокам) пошёл перепроверить курлом - не работает.
Засучил рукава. Перелазил весь инет. Отдебажил эту хрень вплоть до org.apache.tomcat.util.http.fileupload.util.LimitedInputStream - я в запросе тело отправляю, а когда начинает работать StandardServletMultipartResolver - тело куда-то исчезает 😱🤯
Провозился три часа. Потом каким-то чудом, вспомнил, что у нас есть фильтр, который вычитывает тело и прокидыввает дальше обёртку, которая переопределяет getInputStream. А getParts - не переопределяет. И getParts пытается вычитать данные из инпутстрима оригинального HttpServletRequest. Из которого мы уже всё вычитали в фильтре. Занавес.
Были бы силы всё это аккуратно расписать и подать - был бы крутой кейс, почему модель данных должна быть неизменяемой. Но не в этот раз
#whyfp@ergonomic_code #project_r@ergonomic_code
История ужасов про мутабельное состояние.
Есть у нас тут в Проекте Р задачка по загрзуке файла. Отдали её юниору. Он вчера провозился весь день - не осилил загрузить, спринг ругается что не видит multipart part.
Сегодня подключился я. Сделал мастер-класс по ТДД, докинул пару параметров, тест (поверх MockMvc) прошёл. На всякий случай (не верю я этим мокам) пошёл перепроверить курлом - не работает.
Засучил рукава. Перелазил весь инет. Отдебажил эту хрень вплоть до org.apache.tomcat.util.http.fileupload.util.LimitedInputStream - я в запросе тело отправляю, а когда начинает работать StandardServletMultipartResolver - тело куда-то исчезает 😱🤯
Провозился три часа. Потом каким-то чудом, вспомнил, что у нас есть фильтр, который вычитывает тело и прокидыввает дальше обёртку, которая переопределяет getInputStream. А getParts - не переопределяет. И getParts пытается вычитать данные из инпутстрима оригинального HttpServletRequest. Из которого мы уже всё вычитали в фильтре. Занавес.
Были бы силы всё это аккуратно расписать и подать - был бы крутой кейс, почему модель данных должна быть неизменяемой. Но не в этот раз
#whyfp@ergonomic_code #project_r@ergonomic_code
👍10😱2
Привет!
Обещанные демо-проекты.
Project Moby - демо того, как я выкручиваюсь на Spring Data JDCB с энергичной загрузкой, когда она нужна.
Project Sherlok - демо того, как я выкручиваюсь с динамиеческими запросами.
Обе техники используются в Trainer Advisor.
#spring_data_jdbc@ergonomic_code #trainer_advisor@ergonomic_code #demo_projects@ergonomic_code
Обещанные демо-проекты.
Project Moby - демо того, как я выкручиваюсь на Spring Data JDCB с энергичной загрузкой, когда она нужна.
Project Sherlok - демо того, как я выкручиваюсь с динамиеческими запросами.
Обе техники используются в Trainer Advisor.
#spring_data_jdbc@ergonomic_code #trainer_advisor@ergonomic_code #demo_projects@ergonomic_code
GitHub
GitHub - ergonomic-code/Project-Moby: Демонстрационный проект способов энергичной загрузки ссылок в Spring Data Relational (JDBC)
Демонстрационный проект способов энергичной загрузки ссылок в Spring Data Relational (JDBC) - ergonomic-code/Project-Moby
🔥10
Куда выложить записи репетиций докладов?
Anonymous Poll
64%
Youtube
16%
Rutube
14%
VK Video
5%
Что-то ещё?
Привет!
Дайджест первого дня
Лайтенинг удался
Судя по всему.
На докладе был Михаил Поливаха (контрибьютор в SDJ) и после доклада он сказал, что я всё правильно сказал.
А потом ко мне подошёл один из кураторов основного доклада и сказал, что основной доклад был очень хороший, а лайтенинг - ещё лучше.
Ещё на докладе был Владимир Плизга, который после него подписался на канал - Вова, привет! 👋
Олды, которых мы заслужили
Передо мной выступал другой мужик с 20+ опыта и рассказывал о том, как гугл лёгким движением руки превратил их 150+ приложений в легаси убив GWT.
А после моего доклада ведущий выдал что-то в духе "А вы заметили, что про боль в основном говорят мужчины за 30?"
А на следующем докладе девушка сказала, что-то в духе "А вот например жуткие олды с 20+ лет опыта...".
Она говорила про мастеров тату, но всё равно было обидно:)
Зумеры, которых мы заслужили
Та же девушка рассказала, что джуны не только в ИТ, но и в индустрии тату пытаются на голубом глазу продать заказчикам глюки нейронок без какого-либо критического анализа результата.
Поэтому если будете делать тату и вашему мастеру меньше 40 лет - тщательно ревьювьте эскизы на предмет количества пальцев.
В Питере пить
После того как нас выгнали с площадки, затусил с тремя пацанами из Amplicode. Сначала 1.5 часа шарохались по Питеру в поисках открытого после 12 бара/ресторана. Кое-как нашли, выпили по бокалу пива с бургером за 505 рублей с носа и разошлись спать.
Мир, дружба, жвачка
Не смотря на то, что пацанов из Amplicode было больше, я храбро заявил, что не люблю JPA. На что внезапно получил ответ, что из тех кто работает с JPA никто его не любит, а если говорит, что любит - это вызывает вопросики 🤔
Договорились, что зайду на стенд, обещали значки:)
Начинаю отдыхать
Между делом на конфе впервые за долгое время сел снова пописать Trainer Advisor и решил там не совсем тривиальную задачу с тестированием. У меня там пару месяцев назад начали регаться странные боты - регаются на рандомные емейлы и даже залогиниться не пробуют. Их уже штук 30 нарегалось, поэтому меня это начало напрягать и я решил прикрутить капчу. И вот пропихнуть корректную каптчу в интеграционных тестах оказалось не тривиально, чуть позже напишу микропост про это.
Пользуясь случаем, хочу напомнить что мне туда можно поконтрибьютить.
Если вы опытный разработчик и вам не комфортно работать в том стиле, в котором пишете сейчас - это хороший способ пощупать ЭП руками и понять нравится ли вам такой DevX.
Если вы молодой разработчик - это хороший способ получить мой менторинг на реальном проекте в замен за работу. Я очень тщательно провожу ревью и в целом стараюсь давать максимум полезной обратной связи.
Код двух подписчиков уже есть в TA - так что это вполне реально:)
Если интересно - пишите в личку, договоримся о звонке для онбоардинга
Дайджест первого дня
Лайтенинг удался
Судя по всему.
На докладе был Михаил Поливаха (контрибьютор в SDJ) и после доклада он сказал, что я всё правильно сказал.
А потом ко мне подошёл один из кураторов основного доклада и сказал, что основной доклад был очень хороший, а лайтенинг - ещё лучше.
Ещё на докладе был Владимир Плизга, который после него подписался на канал - Вова, привет! 👋
Олды, которых мы заслужили
Передо мной выступал другой мужик с 20+ опыта и рассказывал о том, как гугл лёгким движением руки превратил их 150+ приложений в легаси убив GWT.
А после моего доклада ведущий выдал что-то в духе "А вы заметили, что про боль в основном говорят мужчины за 30?"
А на следующем докладе девушка сказала, что-то в духе "А вот например жуткие олды с 20+ лет опыта...".
Она говорила про мастеров тату, но всё равно было обидно:)
Зумеры, которых мы заслужили
Та же девушка рассказала, что джуны не только в ИТ, но и в индустрии тату пытаются на голубом глазу продать заказчикам глюки нейронок без какого-либо критического анализа результата.
Поэтому если будете делать тату и вашему мастеру меньше 40 лет - тщательно ревьювьте эскизы на предмет количества пальцев.
В Питере пить
После того как нас выгнали с площадки, затусил с тремя пацанами из Amplicode. Сначала 1.5 часа шарохались по Питеру в поисках открытого после 12 бара/ресторана. Кое-как нашли, выпили по бокалу пива с бургером за 505 рублей с носа и разошлись спать.
Мир, дружба, жвачка
Не смотря на то, что пацанов из Amplicode было больше, я храбро заявил, что не люблю JPA. На что внезапно получил ответ, что из тех кто работает с JPA никто его не любит, а если говорит, что любит - это вызывает вопросики 🤔
Договорились, что зайду на стенд, обещали значки:)
Начинаю отдыхать
Между делом на конфе впервые за долгое время сел снова пописать Trainer Advisor и решил там не совсем тривиальную задачу с тестированием. У меня там пару месяцев назад начали регаться странные боты - регаются на рандомные емейлы и даже залогиниться не пробуют. Их уже штук 30 нарегалось, поэтому меня это начало напрягать и я решил прикрутить капчу. И вот пропихнуть корректную каптчу в интеграционных тестах оказалось не тривиально, чуть позже напишу микропост про это.
Пользуясь случаем, хочу напомнить что мне туда можно поконтрибьютить.
Если вы опытный разработчик и вам не комфортно работать в том стиле, в котором пишете сейчас - это хороший способ пощупать ЭП руками и понять нравится ли вам такой DevX.
Если вы молодой разработчик - это хороший способ получить мой менторинг на реальном проекте в замен за работу. Я очень тщательно провожу ревью и в целом стараюсь давать максимум полезной обратной связи.
Код двух подписчиков уже есть в TA - так что это вполне реально:)
Если интересно - пишите в личку, договоримся о звонке для онбоардинга
👍10🔥6
Ещё пункт забыл
Неожиданная встреча
Случайно встретил бывшего студента.
Он рассказал, что следующему поколению советовал идти ко мне на курс по БД. А я не пришел - взял "декрет".
Но все равно приятно - снова задумался вернутся в следующем году.
А ещё (к вопросу про JPA в комментах) рассказал, что у них в большой корпорации пришел СТО, сказал что они не умеют в JPA и теперь они то ли все новое пишут, то ли старое переписывают на SDJ.
#spring_data_jdbc@ergonomic_code
Неожиданная встреча
Случайно встретил бывшего студента.
Он рассказал, что следующему поколению советовал идти ко мне на курс по БД. А я не пришел - взял "декрет".
Но все равно приятно - снова задумался вернутся в следующем году.
А ещё (к вопросу про JPA в комментах) рассказал, что у них в большой корпорации пришел СТО, сказал что они не умеют в JPA и теперь они то ли все новое пишут, то ли старое переписывают на SDJ.
#spring_data_jdbc@ergonomic_code
👍2
Привет!
Фух, "папа вырвался на свободу" наконец-то закончилось. С понедельника спал часов 15 максимум, а не пью первый день.
Но было круто - конфа глазами спикера выглядит намного интереснее, чем участника - советую попробовать.
Я весной попробую податься на snowone или codefest с вариацией на тему одного из докладов Джокера, а осенью попробую опять на Джокере ченить про тестирование рассказать.
Фух, "папа вырвался на свободу" наконец-то закончилось. С понедельника спал часов 15 максимум, а не пью первый день.
Но было круто - конфа глазами спикера выглядит намного интереснее, чем участника - советую попробовать.
Я весной попробую податься на snowone или codefest с вариацией на тему одного из докладов Джокера, а осенью попробую опять на Джокере ченить про тестирование рассказать.
👍17
Привет!
Ну чтош, ютуб решил всё за нас - без подтверждения загрузить видео более чем на 15 минут не даёт и подтвердить акк на мой номер телефона тоже не даёт.
Так что представляю вам свой канал на Рутубе и первый видос на нём - РЕПЕТИЦИЯ доклада "Функциональная архитектура и Spring Data JDBC. 4 года в проде, полёт отличный"
#talks@ergonomic_code #ergo_approach@ergonomic_code #functional_architecture@ergonomic_code #ergo_persistance@ergonomic_code #spring_data_jdbc@ergonomic_code
Ну чтош, ютуб решил всё за нас - без подтверждения загрузить видео более чем на 15 минут не даёт и подтвердить акк на мой номер телефона тоже не даёт.
Так что представляю вам свой канал на Рутубе и первый видос на нём - РЕПЕТИЦИЯ доклада "Функциональная архитектура и Spring Data JDBC. 4 года в проде, полёт отличный"
#talks@ergonomic_code #ergo_approach@ergonomic_code #functional_architecture@ergonomic_code #ergo_persistance@ergonomic_code #spring_data_jdbc@ergonomic_code
RUTUBE
Эргономичный код — полная коллекция видео на RUTUBE
Канал о разработе поддерживаемых бакэндов - модульных монолитов с неизменяемой моделью данных и функциональной архитектурой, написанных в стиле data-oriented programming и покрытых тестами без моков.
https://t.me/ergonomic_code
https://azhidkov.pro
https://t.me/ergonomic_code
https://azhidkov.pro
❤16👍6🤡4
Привет!
Залил на рутуб тестовый прогон своего выступления на конференции Joker'24 от JUG Ru Group.
Официальная запись самого выступления с нормальным звуком будет доступна бесплатно до следующей весны - напишу в канале, как её опубликуют.
#talks@ergonomic_code #ergo_approach@ergonomic_code #structured_design@ergonomic_code
Залил на рутуб тестовый прогон своего выступления на конференции Joker'24 от JUG Ru Group.
Официальная запись самого выступления с нормальным звуком будет доступна бесплатно до следующей весны - напишу в канале, как её опубликуют.
#talks@ergonomic_code #ergo_approach@ergonomic_code #structured_design@ergonomic_code
RUTUBE
РЕПЕТИЦИЯ 241007 - Структурный дизайн. Древний секрет простого и быстрого кода.
Запись последней репетиции моего доклада на Joker 24 от JUG Ru Group (https://jugru.org/).
Страница доклада на сайте конференции: https://jokerconf.com/talks/f9b11eab0fc14bc2b2dc7c3ad62834d0/?referer=%2Fschedule%2Fdays%2F
Страница доклада на сайте конференции: https://jokerconf.com/talks/f9b11eab0fc14bc2b2dc7c3ad62834d0/?referer=%2Fschedule%2Fdays%2F
👍7🤡3
Привет!
Вы когда-нибудь задавались вопросом, почему некоторые разработчики (например анкл Боб в чистой архитектуре) методы или классы, реализующие один эндпонит, называют юзкейсами? Ведь юзкейс - это многошаговый сценарий, в котором каждый шаг - вызов отдельного эндпоинта.
Я - задавался.
А сейчас начал читать матчасть по юзкейсам и узнал почему.
Оказывается, юзкейсы рекурсивны.
На самом верхнем уровне - бизнес юзкейсы (Кокбёрн называет их ещё белыми), они состоят из пользовательских юзкейсов (синие) - это то, что я понимал под юзкейсами -, которые, в свою очередь, состоят из юзкейсов-подфункций (индиго/чёрные) - вот это и есть те самые юзкейсы из чистой архитектуры.
А ещё, кажется, я тут нашёл стратегию декомпозиции слоя приложения - собственно по юзкейсам. Правда она предполагает, что эти самые юз кейсы есть и структурированы, но сейчас у меня такое ощущение, что их наличие - действительно важно для успеха проекта и если это не делает аналитик/бизнес - это должен делать техлид в рамках проектирования.
Ну и книгу я ещё прочитал только процентов на 50, но уже готов её порекомендовать.
#books@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code
Вы когда-нибудь задавались вопросом, почему некоторые разработчики (например анкл Боб в чистой архитектуре) методы или классы, реализующие один эндпонит, называют юзкейсами? Ведь юзкейс - это многошаговый сценарий, в котором каждый шаг - вызов отдельного эндпоинта.
Я - задавался.
А сейчас начал читать матчасть по юзкейсам и узнал почему.
Оказывается, юзкейсы рекурсивны.
На самом верхнем уровне - бизнес юзкейсы (Кокбёрн называет их ещё белыми), они состоят из пользовательских юзкейсов (синие) - это то, что я понимал под юзкейсами -, которые, в свою очередь, состоят из юзкейсов-подфункций (индиго/чёрные) - вот это и есть те самые юзкейсы из чистой архитектуры.
А ещё, кажется, я тут нашёл стратегию декомпозиции слоя приложения - собственно по юзкейсам. Правда она предполагает, что эти самые юз кейсы есть и структурированы, но сейчас у меня такое ощущение, что их наличие - действительно важно для успеха проекта и если это не делает аналитик/бизнес - это должен делать техлид в рамках проектирования.
Ну и книгу я ещё прочитал только процентов на 50, но уже готов её порекомендовать.
#books@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code
👍6🔥1
Forwarded from Spring АйО
При юнит-тестировании часто требуется проверить методы, которые используют цепочки вызовов, например, в WebClient из Spring WebFlux.
⚠️ Если задача позволяет, лучше воспользоваться MockWebServer или WireMock для гибкого тестирования HTTP-клиентов. Здесь WebClient выбран лишь из-за своей наглядности и популярности.
Представим клиент, запрашивающий случайную цитату у удалённого сервиса:
public class InspirationalQuotesClient {
private final WebClient webClient;
public InspirationalQuotesClient(WebClient webClient) {
this.webClient = webClient;
}
public String fetchRandomQuote() {
try {
return this.webClient
.get()
.uri("/api/quotes")
.retrieve()
.bodyToMono(String.class)
.block();
} catch (WebClientException e) {
return "Every time a mock returns, a mock a fairy dies.";
}
}
}
Для тестирования такого клиента стандартным способом нужно замокировать каждый вызов в цепочке, чтобы избежать
NullPointerException
. Это может сделать тест слишком громоздким:
@ExtendWith(MockitoExtension.class)
class InspirationalQuotesClientTest {
@Mock private WebClient webClient;
@InjectMocks private InspirationalQuotesClient cut;
@Test
void shouldReturnInMockingHell() {
WebClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(WebClient.RequestHeadersUriSpec.class);
WebClient.ResponseSpec responseSpec = Mockito.mock(WebClient.ResponseSpec.class);
when(webClient.get()).thenReturn(requestHeadersUriSpec);
when(requestHeadersUriSpec.uri("/api/quotes")).thenReturn(requestHeadersUriSpec);
when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec);
when(responseSpec.bodyToMono(String.class)).thenReturn(Mono.just("We've escaped hell"));
String result = cut.fetchRandomQuote();
assertEquals("We've escaped hell", result);
}
}
Решение? Deep Stubs в Mockito. С ними можно упростить тест, описав всю цепочку вызовов сразу в конструкции
when
. Это значительно уменьшит количество кода:
@ExtendWith(MockitoExtension.class)
class DeepStubClientTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private WebClient webClient;
@InjectMocks private InspirationalQuotesClient cut;
@Test
void shouldReturnQuoteFromRemoteSystem() {
Mockito.when(webClient.get().uri("/api/quotes").retrieve().bodyToMono(String.class))
.thenReturn(Mono.just("Less setup hell - but not better"));
String result = cut.fetchRandomQuote();
assertEquals("Less setup hell - but not better", result);
}
}
Используя параметр
answer = Answers.RETURNS_DEEP_STUBS
, мы возвращаем заглушку для каждого метода в цепочке. Но помните, что этот подход увеличивает зависимость теста от конкретной структуры вызовов, и любые изменения в цепочке потребуют изменений в тесте.P.S. А как вы мокируете вызовы внешних API?
Ставьте 🔥 если считаете функциональность полезной.
Please open Telegram to view this post
VIEW IN TELEGRAM
Привет!
Говорят, чёрный пиар - это тоже пиар, поэтому надеюсь пацаны из Spring АйО (Саша, привет! 👋 ) не сильно обидятся, что я их пост разнесу чутка:)
Пример теста в посте имеет две проблемы
Проблема первая - непонятно, что тестирует этот тест
Вообще, вроде как, он должен тестировать клиента внешней системы. Но фактически, он тестирует не клиента внешней системы, а просто фиксирует вызовы Spring-овго АПИ (читай: детали реализации).
И если внешняя система поменяет формат ответа на json - код сломается, а тест продолжит проходить.
А если я перепишу клиента на restTemplate (и проверю руками) - код будет работать, а тест сломается.
Проблема вторая - он нарушает хрестоматийное правило тестов с моками
Мокайте только собственные типы (см. Growing Object-Oriented Software, Guided by Tests, Chapter 8)
—
Как это надо было делать
Вариант №1: идеальный
Поднять в тестконтейнере latest-версию внешней системы и написать тест, который бы работал с ней.
Такой тест:
1. ни как бы не был завязан на реализацию - вы с внешней системой могли бы хоть на protobuf перейти и в самом тесте вообще ничего менять бы не пришлось
1.1. Как следствие он бы подстраховал вас и если бы вы решили поменять либу для работы с хттп (на тот же RestTemplate, например)
2. поймает ошибки обратной совместимости внешнего АПИ, особенно если его регулярно на CI запускать
3. поймает регрессии в Spring
4. Ну и, очевидно, поймает если нарушите контракт (например, при рефакторинге идея затупит и поменяет слово в пути)
5. а ещё вы сможете его использовать в процессе разработки и соответственно быстро итерироваться с кодом реализации клиента, не рестаруя всё приложение целиком или не костыляя какой-то отдельный main-метод для этих целей
В общем он будет вашим другом - когда и если вы захотите поменять код клиента, он не будет вам мешать просто так и подскажет, если вы что-то сломаете.
Но это (внешняя система в докере) - практически нереальный вариант.
Вариант №2: реальный
Соответственно следующий вариант - написать тест, который работает с тестовым контуром внешней системы. Скорее всего, его придётся засунуть под флаг и запускать только на CI.
Он продолжит быть вашим другом, но и принесёт ряд проблем:
1. скорее всего он будет медленный
2. возможно он будет мигать
3. сообщать о проблемах он будет позже, чем хотелось бы
Вариант №3: cомнительно, но окей
Если варианты выше не возможны, либо не приемлемы (слишком медленно, слишком часто мигает) - можно взять WireMock.
В этом варианте вы потеряете контроль соблюдения контракта вами и внешней системой, но хотя бы останется контроль, соблюдения контракта вами и Spring-ом. Соответственно такой тест подстрахует вас, если вы решите поменять либу работы с ХТТП, либо обновите версию Spring.
Но я бы на такие тесты вообще не заморачивался - это всё будет покрыто тестами, клиентов нашего клиента, которым для работы надо будет, чтобы InspirationalQuotesClient смог взять данные.
Вариант №4: кто-то в интернете считает, что так правильно, но он не прав
Собственно мокисты считают, что правильно:
1. InspirationalQuotesClient покрыть интеграционным тестом (варианты 1-3 выше), либо не покрывать тестами вообще
2. А в тесте клиента InspirationalQuotesClient замокать уже сам InspirationalQuotesClient, а не WebClient
Но на самом деле правильно:
1. операцию, в которой задействован InspirationalQuotesClient покрыть одним интеграционным тестом, который:
1.1. всю управляемую инфраструктуру (БД, очередь сообщений, внутренние сервисы) поднимает в тест контейнерах и работает с ней
1.2. везде где возможно для неуправляемой инфраструктуры поднимает фейки на транспортном уровне (WireMock)
1.3. В самом крайнем случае мокает свои типы, которые абстрагируют внешнюю инфру, которую по другому не симулировать никак
2. Эту операцию сделать сбалансированной
3. И получить возможность всю бизнес-логику (которая даже косвенно через интерфейсы не зависит от внешних систем) покрыть чистыми юнит тестами, без спринга, моков, тестконтейнеров и т.д.
#ergo_testing@ergonomic_code
Говорят, чёрный пиар - это тоже пиар, поэтому надеюсь пацаны из Spring АйО (Саша, привет! 👋 ) не сильно обидятся, что я их пост разнесу чутка:)
Пример теста в посте имеет две проблемы
Проблема первая - непонятно, что тестирует этот тест
Вообще, вроде как, он должен тестировать клиента внешней системы. Но фактически, он тестирует не клиента внешней системы, а просто фиксирует вызовы Spring-овго АПИ (читай: детали реализации).
И если внешняя система поменяет формат ответа на json - код сломается, а тест продолжит проходить.
А если я перепишу клиента на restTemplate (и проверю руками) - код будет работать, а тест сломается.
Проблема вторая - он нарушает хрестоматийное правило тестов с моками
Мокайте только собственные типы (см. Growing Object-Oriented Software, Guided by Tests, Chapter 8)
—
Как это надо было делать
Вариант №1: идеальный
Поднять в тестконтейнере latest-версию внешней системы и написать тест, который бы работал с ней.
Такой тест:
1. ни как бы не был завязан на реализацию - вы с внешней системой могли бы хоть на protobuf перейти и в самом тесте вообще ничего менять бы не пришлось
1.1. Как следствие он бы подстраховал вас и если бы вы решили поменять либу для работы с хттп (на тот же RestTemplate, например)
2. поймает ошибки обратной совместимости внешнего АПИ, особенно если его регулярно на CI запускать
3. поймает регрессии в Spring
4. Ну и, очевидно, поймает если нарушите контракт (например, при рефакторинге идея затупит и поменяет слово в пути)
5. а ещё вы сможете его использовать в процессе разработки и соответственно быстро итерироваться с кодом реализации клиента, не рестаруя всё приложение целиком или не костыляя какой-то отдельный main-метод для этих целей
В общем он будет вашим другом - когда и если вы захотите поменять код клиента, он не будет вам мешать просто так и подскажет, если вы что-то сломаете.
Но это (внешняя система в докере) - практически нереальный вариант.
Вариант №2: реальный
Соответственно следующий вариант - написать тест, который работает с тестовым контуром внешней системы. Скорее всего, его придётся засунуть под флаг и запускать только на CI.
Он продолжит быть вашим другом, но и принесёт ряд проблем:
1. скорее всего он будет медленный
2. возможно он будет мигать
3. сообщать о проблемах он будет позже, чем хотелось бы
Вариант №3: cомнительно, но окей
Если варианты выше не возможны, либо не приемлемы (слишком медленно, слишком часто мигает) - можно взять WireMock.
В этом варианте вы потеряете контроль соблюдения контракта вами и внешней системой, но хотя бы останется контроль, соблюдения контракта вами и Spring-ом. Соответственно такой тест подстрахует вас, если вы решите поменять либу работы с ХТТП, либо обновите версию Spring.
Но я бы на такие тесты вообще не заморачивался - это всё будет покрыто тестами, клиентов нашего клиента, которым для работы надо будет, чтобы InspirationalQuotesClient смог взять данные.
Вариант №4: кто-то в интернете считает, что так правильно, но он не прав
Собственно мокисты считают, что правильно:
1. InspirationalQuotesClient покрыть интеграционным тестом (варианты 1-3 выше), либо не покрывать тестами вообще
2. А в тесте клиента InspirationalQuotesClient замокать уже сам InspirationalQuotesClient, а не WebClient
Но на самом деле правильно:
1. операцию, в которой задействован InspirationalQuotesClient покрыть одним интеграционным тестом, который:
1.1. всю управляемую инфраструктуру (БД, очередь сообщений, внутренние сервисы) поднимает в тест контейнерах и работает с ней
1.2. везде где возможно для неуправляемой инфраструктуры поднимает фейки на транспортном уровне (WireMock)
1.3. В самом крайнем случае мокает свои типы, которые абстрагируют внешнюю инфру, которую по другому не симулировать никак
2. Эту операцию сделать сбалансированной
3. И получить возможность всю бизнес-логику (которая даже косвенно через интерфейсы не зависит от внешних систем) покрыть чистыми юнит тестами, без спринга, моков, тестконтейнеров и т.д.
#ergo_testing@ergonomic_code
Telegram
Эргономичный код
🔗 Создание Deep Stubs в Mockito
При юнит-тестировании часто требуется проверить методы, которые используют цепочки вызовов, например, в WebClient из Spring WebFlux.
⚠️ Если задача позволяет, лучше воспользоваться MockWebServer или WireMock для гибкого тестирования…
При юнит-тестировании часто требуется проверить методы, которые используют цепочки вызовов, например, в WebClient из Spring WebFlux.
⚠️ Если задача позволяет, лучше воспользоваться MockWebServer или WireMock для гибкого тестирования…
👍4❤3
Что ещё почитать на тему тестирования
Принципы юнит тестирования - самая крутая книга на эту тему
TDD Revisited - Ian Cooper - NDC Porto 2023 - суть здорового тестирования за час пятнадцать
Пачка постов у меня про тестирование Trainer Advisor
Подборки постов у меня в канале - #tdd #nomocks
#ergo_testing@ergonomic_code #books@ergonomic_code #talks@ergonomic_code #posts@ergonomic_code
Принципы юнит тестирования - самая крутая книга на эту тему
TDD Revisited - Ian Cooper - NDC Porto 2023 - суть здорового тестирования за час пятнадцать
Пачка постов у меня про тестирование Trainer Advisor
Подборки постов у меня в канале - #tdd #nomocks
#ergo_testing@ergonomic_code #books@ergonomic_code #talks@ergonomic_code #posts@ergonomic_code
www.piter.com
Принципы юнит-тестирования
Практика модульного тестирования - это практическое руководство по современным методам модульного тестирования.
👍9