Настроить компонент @MockBean до запуска приложения

У меня есть приложение Spring Boot 1.4.2. Некоторый код, который используется во время запуска, выглядит следующим образом:

@Component 
class SystemTypeDetector{
    public enum SystemType{ TYPE_A, TYPE_B, TYPE_C }
    public SystemType getSystemType(){ return ... }
}

@Component 
public class SomeOtherComponent{
    @Autowired 
    private SystemTypeDetector systemTypeDetector;
    @PostConstruct 
    public void startup(){
        switch(systemTypeDetector.getSystemType()){   // <-- NPE here in test
        case TYPE_A: ...
        case TYPE_B: ...
        case TYPE_C: ...
        }
    }
}

Есть компонент, который определяет тип системы. Этот компонент используется во время запуска из других компонентов. В производстве все работает отлично.

Теперь я хочу добавить несколько интеграционных тестов, используя Spring 1.4 @MockBean.

Тест выглядит так:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyWebApplication.class, webEnvironment = RANDOM_PORT)
public class IntegrationTestNrOne {
    @MockBean 
    private SystemTypeDetector systemTypeDetectorMock;

    @Before 
    public void initMock(){
       Mockito.when(systemTypeDetectorMock.getSystemType()).thenReturn(TYPE_C);
    }

    @Test 
    public void testNrOne(){
      // ...
    }
}

В основном издевательство работает отлично. Мой systemTypeDetectorMock используется, и если я вызываю getSystemTypeTYPE_C возвращается.

Проблема в том, что приложение не запускается. На данный момент рабочий порядок пружин вроде бы:

  1. создать все Mocks (без конфигурации все методы возвращают ноль)
  2. запустить приложение
  3. call @Before-методы (где будут настраиваться макеты)
  4. начать тест

Моя проблема в том, что приложение запускается с неинициализированным макетом. Таким образом, вызов getSystemType() возвращает getSystemType().

Мой вопрос: как я могу настроить макеты перед запуском приложения?

Изменить: Если у кого-то есть такая же проблема, один из обходных путей должен использовать @MockBean(answer = CALLS_REAL_METHODS). Это вызывает реальный компонент, и в моем случае система запускается. После запуска я могу изменить макет поведения.

Ответ 1

Класс SomeOtherComponent также требует аннотацию @Component.

Ответ 2

Я думаю, что это связано с тем, как вы автоматически связываете свои зависимости. Взгляните на это (особенно часть "Исправление № 1: решите ваш дизайн и сделайте ваши зависимости видимыми"). Таким образом, вы также можете избежать использования @PostConstruct и просто использовать конструктор.