Почему в Spring используют конфигурации и автосвязывание бинов вместо создания объектов через конструкторы
Что проверяют
Автоматизатор на Java живёт внутри контекста Spring: тесты поднимают приложение, подменяют бины, ходят в базу из контейнера. Проверяют, понимаете ли вы, что даёт контейнер кроме красоты, и умеете ли подменить зависимость в тесте, не трогая рабочий код.
Как отвечать
Сначала снять ложное противопоставление: Spring не отменяет конструкторы, он их и вызывает. Конструкторное внедрение это рекомендуемый способ, контейнер сам передаёт зависимости аргументами. Спор идёт не про «конструктор или контейнер», а про то, кто решает, какая именно реализация подставится.
Дальше по делу, что даёт контейнер:
- единая точка сборки графа зависимостей: класс не знает, откуда взялся клиент базы, и в тесте на его место встаёт заглушка;
- жизненный цикл и область видимости: по умолчанию бин это синглтон на контекст, и этим можно управлять;
- конфигурация профилем:
@Profileи отдельныйapplication-test.ymlменяют адрес стенда и реализацию без правок кода; - готовые точки подмены в тестах:
@TestConfiguration,@MockBean(в свежих версиях его заменяет@MockitoBean),@DynamicPropertySourceдля адреса поднятого контейнера с базой.
Сильный финал: не любой тест обязан поднимать контекст. Если класс собран через конструктор, чистый модульный тест создаёт его руками с моками, вообще без Spring, и работает на порядок быстрее.
Где спотыкаются
Внедряют через поле с @Autowired, а потом не могут создать объект в модульном тесте: конструктора с зависимостями нет, поле приватное, приходится тащить рефлексию. Конструктор снимает проблему сам.
Второе: ставят @MockBean в каждом тестовом классе и удивляются, почему прогон идёт минутами. Каждая уникальная комбинация подмен и настроек это отдельный контекст, кэш Spring его не переиспользует, и приложение поднимается заново.
Третье: забывают, что синглтон общий на весь контекст. Тест, который положил что-то в поле бина или настроил мок, влияет на соседний, и падения выглядят плавающими. Лечится точечным @DirtiesContext или отказом от изменяемого состояния в бине.