Поддерживаю написанное выше, на нашем проекте со временем пришли к тем же выводам. Дополню несколько интересных моментов.
Использовать Spring-контекст гарантированно один раз за прогон всех тестов помогает вот такая простая штука:
@Slf4j
public class FailFastContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final AtomicBoolean flag = new AtomicBoolean();
@SuppressFBWarnings("DM_EXIT")
@Override
public void initialize(@NonNull ConfigurableApplicationContext applicationContext) {
boolean error = flag.getAndSet(true);
if (error) {
// throw new IllegalStateException("Second application context start attempt.");
log.error("""
Second application context start attempt.
####################################################
# SECOND APPLICATION CONTEXT START ATTEMPT. #
# ----------------------------------------- #
# Please look upper for the reason why Spring is #
# trying to recreate test context. This can be #
# caused by adding an @Import/@MockBean and some #
# other annotations to the test class. #
# #
# This process will now exit immediately. #
####################################################
""");
System.exit(-1);
}
}
}
Нужно только подложить его в @ContextConfiguration(initializers={...}) на главном тестовом классе приложения BaseApplicationTest (от которого удобно наследовать все непосредственно тестовые классы).
Вызовы своего боевого API совершаем через честный http-клиент. Это даёт небольшие накладные расходы на сериализацию/десериализацию, зато дополнительно покрывает: конфигурацию Jackson (кто не ловил, что Instant сериализуется в массив чисел?), цепочку фильтров (особенно если подложены свои фильтры), настройки приложения (вкл/выкл OSiV?) и т.п. В общем, успешно пройденный тест даёт ещё больше гарантий, чем вызов напрямую контроллеров.
Иногда (в полной мере этого слова) — всё-таки приходится искать способы внедрить какие-то ассерты в кишки боевого кода. Для этого можно придумать отдельный интерфейс, похожий на обычные функциональные (Function, Consumer, Supplier, в зависимости от вашей ситуации), и инжектить в боевой код Optional<ThisInterface> и дёргать в нужном месте. Естественно, в боевом контексте не будет реализации и ничего выполняться не будет. В тестах подкладывать собственную реализацию этого интерфейса, инжектить в свой тестовый класс, использовать. Обычно внутри реализации прячется какой-нибудь Exchange, AtomicReference или какой-то такой примитив для обмена данными.
Не стесняйтесь в тестовом коде писать свои контроллеры, сервисы и даже репозитории. Все они могут помочь не строить костыли. Или можно написать просто класс-accessor для package-private данных в каком-то боевом пакете, просто расположив его в нём же и сделав публичным. Сделать какой-то боевой код (классы, методы) package-private вместо private — может быть приемлемым компромиссом в ряде случаев. Я тогда в комментариях так и пишу "Является package-private для целей тестирования".
Ну и самая пушка в нашем проекте — гарантия от тестовой инфраструктуры в сторону теста, что БД всегда чиста. Требует некоторое время для реализации, даёт некоторые накладные расходы, зато как приятно ощущать, что тест действительно изолирован от остальных. Очень радует и при написании новых, и при исправлении имеющихся.
В заключении хочется повторить Uncle Боба — относитесь к коду своих тестов также, как к боевому, и ни в коем случае не как к коду второго сорта.
Тут есть некий замкнутый круг, что бы понять, что best practice — вот он, нужно сначала узнать основы, в какой-то мере и плохие практики тоже нужно сначала увидеть.
Все эти номера версий с уже давно почившим временем жизни оставляют какую-то неприятную нотку. От 16 до 17 один релиз, критичного ничего не добавляли, зато отношение было бы куда лучше. ИМХО.
Я вас понял. Что тут можно сказать ... одной такой ситуацией в стране больше, одной меньше. Да, с точки зрения закона преступление. По-хорошему, либо наказывать, но тогда кто-то должен это как-то проинициировать (но пока, похоже, это никому не интересно сделать), либо наоборот -- легализовать.
Аналогичных ситуаций в стране множество -- взять тех же застройщиков или ремонтников, что работают в черную, хотя должны платить налоги, или мб даже какие-то "серые программистские галеры". Нарушения закона, которые всеми соблюдаются и никак не наказываются, плюс время от времени появляются новые. Но, как я думаю, прокат спираченных фильмов -- это не самая большая проблема в стране, при появлении которой нужно тут же начинать с ней бороться, бросив всё.
При желании, вы можете сходить на такой фильм и написать заявление на незаконность происходящего.
Ну, самоопределение в маргиналы или не в них -- тоже дискуссионный вопрос. В каких-то странах могут смотреть только пиратское, в т.ч. и в кинотеатрах, в каких-то -- смотреть дома пиратку тоже будет зашкваром. Мир богат и разнообразен. Даже нахождение посередине будет восприниматься маргинальностью как со стороны одного края, так и со стороны другого.
Про "стандартное": скорее не так. Я не советую воровать. Меня тоже не очень радует ситуация, куда всё идёт. Но, оказавшись в какой-то не очень комфортной ситуации (или находясь в ней долгое время) не имеет смысла её отрицать, пытаться не видеть. А попытки указать на объективное её наличие -- её поддержкой.
Применительно к кинотеатрам. Год назад кинотеатры процветали, было много фильмов, зрителей, стало много и самих кинотеатров, и каких-то сопутствующих им вещей, та же продажа попкорна, условно. Рынок вырос и на нём были трудовые места. Сейчас всё упало, а людям надо платить зарплату. Или увольнять, увеличивая безработицу. Вот можем мы с вами гарантировано сказать, что все кинотеатры наживаются на пиратских показах, или все они делают это, чтобы поддержать оборот и людей на рабочих местах? Истина будет где-то посередине, но в обсуждениях обычно рассматриваются только крайности.
Детей обычно учат идеалам, так принято. По мере взросления обычно приходит понимание о неидеальности мира. Невозможно быть сильно правильнее других. Можно быть немного правильнее и подталкивать других в сторону правильности. Если все воруют, а вы нет -- долго не протянете. Если воруют немногие, то скорее всего можно жить не воруя. И в целом как система стремиться к постепенному уменьшению воровства и сведению его на нет.
Добавлю, что читать длинные строки трудно. Вместо того, чтобы читать код в плоскости высота+ширина (и тем более листать вправо), легче воспринимаются более вертикальные, одноразмерные конструкции. IMHO, в примере выше разбиение по строкам несколько помогает.
А вообще, тут ещё режет не длина, а отсутствие смысла. Смесь смысла и не-смысла. Если вместо абстрактных superLongVarNameWithAdditionalInfo и anotherOneLongVarName подставить бизнесовые смыслы, внезапно формула становится эмоционально приятнее.
Чем eclipse-temurin лучше, чем, например, bellsoft/liberica-jdk-alpine-musl? Последний видимо будет ещё меньше в размере.
Вариант с копированием такого банального инструмента, как мавен, имхо, следовало бы дожать до сборки своего тулинг-образа, или хотя бы поиска подходящего в интернете.
Потому что детское кресло водителю нужно купить за свои деньги, возить, занимая место в салоне/багажнике, и дети -- риск загрязнения салона ... Ну я это так вижу. Машины с детскими креслами более редкие, значит и дороже.
Тоже за 2 недели раза три помог мне найти решение, над которым не хотелось ломать голову.
Ухи, ухи ...
Поддерживаю написанное выше, на нашем проекте со временем пришли к тем же выводам. Дополню несколько интересных моментов.
Использовать Spring-контекст гарантированно один раз за прогон всех тестов помогает вот такая простая штука:
Нужно только подложить его в
@ContextConfiguration(initializers={...})
на главном тестовом классе приложения BaseApplicationTest (от которого удобно наследовать все непосредственно тестовые классы).Вызовы своего боевого API совершаем через честный http-клиент. Это даёт небольшие накладные расходы на сериализацию/десериализацию, зато дополнительно покрывает: конфигурацию Jackson (кто не ловил, что Instant сериализуется в массив чисел?), цепочку фильтров (особенно если подложены свои фильтры), настройки приложения (вкл/выкл OSiV?) и т.п. В общем, успешно пройденный тест даёт ещё больше гарантий, чем вызов напрямую контроллеров.
Иногда (в полной мере этого слова) — всё-таки приходится искать способы внедрить какие-то ассерты в кишки боевого кода. Для этого можно придумать отдельный интерфейс, похожий на обычные функциональные (Function, Consumer, Supplier, в зависимости от вашей ситуации), и инжектить в боевой код Optional<ThisInterface> и дёргать в нужном месте. Естественно, в боевом контексте не будет реализации и ничего выполняться не будет. В тестах подкладывать собственную реализацию этого интерфейса, инжектить в свой тестовый класс, использовать. Обычно внутри реализации прячется какой-нибудь Exchange, AtomicReference или какой-то такой примитив для обмена данными.
Не стесняйтесь в тестовом коде писать свои контроллеры, сервисы и даже репозитории. Все они могут помочь не строить костыли. Или можно написать просто класс-accessor для package-private данных в каком-то боевом пакете, просто расположив его в нём же и сделав публичным. Сделать какой-то боевой код (классы, методы) package-private вместо private — может быть приемлемым компромиссом в ряде случаев. Я тогда в комментариях так и пишу "Является package-private для целей тестирования".
Ну и самая пушка в нашем проекте — гарантия от тестовой инфраструктуры в сторону теста, что БД всегда чиста. Требует некоторое время для реализации, даёт некоторые накладные расходы, зато как приятно ощущать, что тест действительно изолирован от остальных. Очень радует и при написании новых, и при исправлении имеющихся.
В заключении хочется повторить Uncle Боба — относитесь к коду своих тестов также, как к боевому, и ни в коем случае не как к коду второго сорта.
Тут есть некий замкнутый круг, что бы понять, что best practice — вот он, нужно сначала узнать основы, в какой-то мере и плохие практики тоже нужно сначала увидеть.
Джава ускорилась, и JebBrains приходится больше сил тратить на её поддержку в IDEA, чем развивать Котлин :)
Здесь так много тех, кто любит минусовать и не аргументировать :)
Ждём, пока ломбок подтянется, и в прод!
Все эти номера версий с уже давно почившим временем жизни оставляют какую-то неприятную нотку. От 16 до 17 один релиз, критичного ничего не добавляли, зато отношение было бы куда лучше. ИМХО.
Ломбок прекрасная вещь :)
Пришлось читать примерно три дня :)
Классное время было :)
Я вас понял. Что тут можно сказать ... одной такой ситуацией в стране больше, одной меньше. Да, с точки зрения закона преступление. По-хорошему, либо наказывать, но тогда кто-то должен это как-то проинициировать (но пока, похоже, это никому не интересно сделать), либо наоборот -- легализовать.
Аналогичных ситуаций в стране множество -- взять тех же застройщиков или ремонтников, что работают в черную, хотя должны платить налоги, или мб даже какие-то "серые программистские галеры". Нарушения закона, которые всеми соблюдаются и никак не наказываются, плюс время от времени появляются новые. Но, как я думаю, прокат спираченных фильмов -- это не самая большая проблема в стране, при появлении которой нужно тут же начинать с ней бороться, бросив всё.
При желании, вы можете сходить на такой фильм и написать заявление на незаконность происходящего.
Ну, самоопределение в маргиналы или не в них -- тоже дискуссионный вопрос. В каких-то странах могут смотреть только пиратское, в т.ч. и в кинотеатрах, в каких-то -- смотреть дома пиратку тоже будет зашкваром. Мир богат и разнообразен. Даже нахождение посередине будет восприниматься маргинальностью как со стороны одного края, так и со стороны другого.
Про "стандартное": скорее не так. Я не советую воровать. Меня тоже не очень радует ситуация, куда всё идёт. Но, оказавшись в какой-то не очень комфортной ситуации (или находясь в ней долгое время) не имеет смысла её отрицать, пытаться не видеть. А попытки указать на объективное её наличие -- её поддержкой.
Применительно к кинотеатрам. Год назад кинотеатры процветали, было много фильмов, зрителей, стало много и самих кинотеатров, и каких-то сопутствующих им вещей, та же продажа попкорна, условно. Рынок вырос и на нём были трудовые места. Сейчас всё упало, а людям надо платить зарплату. Или увольнять, увеличивая безработицу. Вот можем мы с вами гарантировано сказать, что все кинотеатры наживаются на пиратских показах, или все они делают это, чтобы поддержать оборот и людей на рабочих местах? Истина будет где-то посередине, но в обсуждениях обычно рассматриваются только крайности.
Когда-нибудь дойдут до рефинансирования, интересно? Или если "успел" купить, всё, на крючке?
Детей обычно учат идеалам, так принято. По мере взросления обычно приходит понимание о неидеальности мира. Невозможно быть сильно правильнее других. Можно быть немного правильнее и подталкивать других в сторону правильности. Если все воруют, а вы нет -- долго не протянете. Если воруют немногие, то скорее всего можно жить не воруя. И в целом как система стремиться к постепенному уменьшению воровства и сведению его на нет.
Имхо :)
Добавлю, что читать длинные строки трудно. Вместо того, чтобы читать код в плоскости высота+ширина (и тем более листать вправо), легче воспринимаются более вертикальные, одноразмерные конструкции. IMHO, в примере выше разбиение по строкам несколько помогает.
А вообще, тут ещё режет не длина, а отсутствие смысла. Смесь смысла и не-смысла. Если вместо абстрактных superLongVarNameWithAdditionalInfo и anotherOneLongVarName подставить бизнесовые смыслы, внезапно формула становится эмоционально приятнее.
Но в целом, конечно, да. Короткие скоупы -- очень хорошо. Иногда и i имеет право на жизнь, хотя я стараюсь всё-таки писать orderId :)
Чем eclipse-temurin лучше, чем, например, bellsoft/liberica-jdk-alpine-musl? Последний видимо будет ещё меньше в размере.
Вариант с копированием такого банального инструмента, как мавен, имхо, следовало бы дожать до сборки своего тулинг-образа, или хотя бы поиска подходящего в интернете.
В какой из этих или других книг написано, как разговаривать с безопасниками, которым хлебом не коми, дай всё запретить? :)
Да не так уж они и страшны. Строчки в файлах вполне себе бесплатны :)
Потому что детское кресло водителю нужно купить за свои деньги, возить, занимая место в салоне/багажнике, и дети -- риск загрязнения салона ... Ну я это так вижу. Машины с детскими креслами более редкие, значит и дороже.