Неприятным сюрпризом оказалось поведение аннотации @ConditionalOnMissingBean. Казалось бы, название говорит о том, что бин добавляется в контекст только тогда, когда нет бина с таким же классом (или с классом, который указан в параметре аннотации).

Т.е. если есть

@Configuration
class MainConfiguration

@ConditionalOnMissingBean(MainConfiguration::class)
@Configuration
class TestConfiguration

то TestConfiguration загрузится только в случае, если в контексте нет MainConfiguration. Однако если переименовать TestConfigurationConfigurationTest, то будут загружены обе конфигурации. WTF, переименование класса ломает функциональность?

На самом деле, все очень просто: загрузка бинов в контекст по умолчанию производится в лексикографическом порядке, а @ConditionalOnMissingBean смотрит только на контекст, загруженный на данный момент, и во втором случае бин MainConfiguration действительно пока еще не создан при загрузке ConfigurationTest. Конечно, документация явно говорит об этом и предлагает использовать @ConditionalOnMissingBean только для автоконфигураций. Решить эту проблему можно явной аннотацией @Order или профилями, но сделать это можно только для контролируемых классов. И ради тестов такое делать — перебор. Но ни через какой @Conditional это сделать не получится, т.к. он не влияет на порядок загрузки бинов.