All streams
Search
Write a publication
Pull to refresh
10
0
Станислав @SimSonic

Душный погромист

Send message

Тоже за 2 недели раза три помог мне найти решение, над которым не хотелось ломать голову.

Поддерживаю написанное выше, на нашем проекте со временем пришли к тем же выводам. Дополню несколько интересных моментов.

Использовать 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 — вот он, нужно сначала узнать основы, в какой-то мере и плохие практики тоже нужно сначала увидеть.

Джава ускорилась, и JebBrains приходится больше сил тратить на её поддержку в IDEA, чем развивать Котлин :)

Здесь так много тех, кто любит минусовать и не аргументировать :)

Ждём, пока ломбок подтянется, и в прод!

Все эти номера версий с уже давно почившим временем жизни оставляют какую-то неприятную нотку. От 16 до 17 один релиз, критичного ничего не добавляли, зато отношение было бы куда лучше. ИМХО.

Ломбок прекрасная вещь :)

Я вас понял. Что тут можно сказать ... одной такой ситуацией в стране больше, одной меньше. Да, с точки зрения закона преступление. По-хорошему, либо наказывать, но тогда кто-то должен это как-то проинициировать (но пока, похоже, это никому не интересно сделать), либо наоборот -- легализовать.

Аналогичных ситуаций в стране множество -- взять тех же застройщиков или ремонтников, что работают в черную, хотя должны платить налоги, или мб даже какие-то "серые программистские галеры". Нарушения закона, которые всеми соблюдаются и никак не наказываются, плюс время от времени появляются новые. Но, как я думаю, прокат спираченных фильмов -- это не самая большая проблема в стране, при появлении которой нужно тут же начинать с ней бороться, бросив всё.

При желании, вы можете сходить на такой фильм и написать заявление на незаконность происходящего.

Ну, самоопределение в маргиналы или не в них -- тоже дискуссионный вопрос. В каких-то странах могут смотреть только пиратское, в т.ч. и в кинотеатрах, в каких-то -- смотреть дома пиратку тоже будет зашкваром. Мир богат и разнообразен. Даже нахождение посередине будет восприниматься маргинальностью как со стороны одного края, так и со стороны другого.

Про "стандартное": скорее не так. Я не советую воровать. Меня тоже не очень радует ситуация, куда всё идёт. Но, оказавшись в какой-то не очень комфортной ситуации (или находясь в ней долгое время) не имеет смысла её отрицать, пытаться не видеть. А попытки указать на объективное её наличие -- её поддержкой.

Применительно к кинотеатрам. Год назад кинотеатры процветали, было много фильмов, зрителей, стало много и самих кинотеатров, и каких-то сопутствующих им вещей, та же продажа попкорна, условно. Рынок вырос и на нём были трудовые места. Сейчас всё упало, а людям надо платить зарплату. Или увольнять, увеличивая безработицу. Вот можем мы с вами гарантировано сказать, что все кинотеатры наживаются на пиратских показах, или все они делают это, чтобы поддержать оборот и людей на рабочих местах? Истина будет где-то посередине, но в обсуждениях обычно рассматриваются только крайности.

Когда-нибудь дойдут до рефинансирования, интересно? Или если "успел" купить, всё, на крючке?

Детей обычно учат идеалам, так принято. По мере взросления обычно приходит понимание о неидеальности мира. Невозможно быть сильно правильнее других. Можно быть немного правильнее и подталкивать других в сторону правильности. Если все воруют, а вы нет -- долго не протянете. Если воруют немногие, то скорее всего можно жить не воруя. И в целом как система стремиться к постепенному уменьшению воровства и сведению его на нет.

Имхо :)

Добавлю, что читать длинные строки трудно. Вместо того, чтобы читать код в плоскости высота+ширина (и тем более листать вправо), легче воспринимаются более вертикальные, одноразмерные конструкции. IMHO, в примере выше разбиение по строкам несколько помогает.

avgDeliveryOrderFulfillmentTime = superLongVarNameWithAdditionalInfo
                                  + anotherOneLongVarName / 2;

А вообще, тут ещё режет не длина, а отсутствие смысла. Смесь смысла и не-смысла. Если вместо абстрактных superLongVarNameWithAdditionalInfo и anotherOneLongVarName подставить бизнесовые смыслы, внезапно формула становится эмоционально приятнее.

avgDeliveryOrderFulfillmentTime = avgOrderCookingAndPackagingTime
                                  + maxOrderCourierDeliveryTime / 2;

Но в целом, конечно, да. Короткие скоупы -- очень хорошо. Иногда и i имеет право на жизнь, хотя я стараюсь всё-таки писать orderId :)

Чем eclipse-temurin лучше, чем, например, bellsoft/liberica-jdk-alpine-musl? Последний видимо будет ещё меньше в размере.

Вариант с копированием такого банального инструмента, как мавен, имхо, следовало бы дожать до сборки своего тулинг-образа, или хотя бы поиска подходящего в интернете.

В какой из этих или других книг написано, как разговаривать с безопасниками, которым хлебом не коми, дай всё запретить? :)

Да не так уж они и страшны. Строчки в файлах вполне себе бесплатны :)

Потому что детское кресло водителю нужно купить за свои деньги, возить, занимая место в салоне/багажнике, и дети -- риск загрязнения салона ... Ну я это так вижу. Машины с детскими креслами более редкие, значит и дороже.

Information

Rating
6,295-th
Location
Новосибирск, Новосибирская обл., Россия
Date of birth
Registered
Activity

Specialization

Backend Developer
Lead
From 500,000 ₽
Java
Spring Boot
PostgreSQL
MySQL
Docker
Kubernetes
CI/CD