Рубрики
Без рубрики

Предотвращение примененияRunner или CommandLineRunner фасоль от выполнения во время тестирования Junit

Узнайте, как предотвратить выполнение бобов ApplicationRunner или CommandLineRunner во время тестов JUnit.

Автор оригинала: baeldung.

1. Обзор

В этом учебнике мы покажем, как мы можем предотвратить бобы типа ПриложениеРаннер или CommandLineRunner от запуска во время интеграционных тестов Spring Boot.

2. Пример применения

Наше примерное приложение состоит из бегуна командной строки, бегуна приложений и фасоли службы задач.

Бегущий по командной строке вызывает команду службы выполнить метод, для выполнения задачи по запуску приложения:

@Component
public class CommandLineTaskExecutor implements CommandLineRunner {
    private TaskService taskService;

    public CommandLineTaskExecutor(TaskService taskService) {
        this.taskService = taskService;
    }

    @Override
    public void run(String... args) throws Exception {
        taskService.execute("command line runner task");
    }
}

Таким же образом бегун приложения взаимодействует со службой задач для выполнения другой задачи:

@Component
public class ApplicationRunnerTaskExecutor implements ApplicationRunner {
    private TaskService taskService;

    public ApplicationRunnerTaskExecutor(TaskService taskService) {
        this.taskService = taskService;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        taskService.execute("application runner task");
    }
}

Наконец, служба задач отвечает за выполнение задач своего клиента:

@Service
public class TaskService {
    private static Logger logger = LoggerFactory.getLogger(TaskService.class);

    public void execute(String task) {
        logger.info("do " + task);
    }
}

И, у нас также есть класс приложения Spring Boot, что делает все это работает:

@SpringBootApplication
public class ApplicationCommandLineRunnerApp {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationCommandLineRunnerApp.class, args);
    }
}

3. Тестирование ожидаемого поведения

тем ПриложениеRunnerTaskExecutor и CommandLineTaskExecutor вы запустите после того, как Spring Boot загружает контекст приложения.

Мы можем проверить это с помощью простого теста:

@SpringBootTest
class RunApplicationIntegrationTest {
    @SpyBean
    ApplicationRunnerTaskExecutor applicationRunnerTaskExecutor;
    @SpyBean
    CommandLineTaskExecutor commandLineTaskExecutor;

    @Test
    void whenContextLoads_thenRunnersRun() throws Exception {
        verify(applicationRunnerTaskExecutor, times(1)).run(any());
        verify(commandLineTaskExecutor, times(1)).run(any());
    }
}

Как мы видим, мы используем Шпионский аннотация для применения Мокито шпионов в ПриложениеRunnerTaskExecutor и CommandLineTaskExecutor фасоль. Поступая таким образом, мы можем проверить, что запустить метод каждой из этих бобов был назван один раз.

В следующих разделах мы увидим различные способы и методы предотвращения такого поведения по умолчанию во время наших интеграционных тестов Spring Boot.

4. Профилактика с помощью весенних профилей

Один из способов, который мы можем предотвратить эти два от запуска, аннотируя их @Profile :

@Profile("!test")
@Component
public class CommandLineTaskExecutor implements CommandLineRunner {
    // same as before
}
@Profile("!test")
@Component
public class ApplicationRunnerTaskExecutor implements ApplicationRunner {
    // same as before
}

После вышеуказанных изменений мы приступаем к нашему интеграционному тесту:

@ActiveProfiles("test")
@SpringBootTest
class RunApplicationWithTestProfileIntegrationTest {
    @Autowired
    private ApplicationContext context;

    @Test
    void whenContextLoads_thenRunnersAreNotLoaded() {
        assertNotNull(context.getBean(TaskService.class));
        assertThrows(NoSuchBeanDefinitionException.class, 
          () -> context.getBean(CommandLineTaskExecutor.class), 
          "CommandLineRunner should not be loaded during this integration test");
        assertThrows(NoSuchBeanDefinitionException.class, 
          () -> context.getBean(ApplicationRunnerTaskExecutor.class), 
          "ApplicationRunner should not be loaded during this integration test");
    }
}

Как мы видим, мы аннотировали вышеуказанный тестовый класс с @ActiveProfiles (“тест”) аннотация, что означает, что она не будет проволоки тех, аннотированных @Profile (“!тест”) . В результате ни один из CommandLineTaskExecutor фасоль, ни ПриложениеRunnerTaskExecutor фасоль загружается на всех.

5. Профилактика с помощью Аннотации УсловногоНаПропертии

Или мы можем настроить их проводку по свойству, а затем использовать аннотацию ConditionalOnProperty:

@ConditionalOnProperty(
  prefix = "application.runner", 
  value = "enabled", 
  havingValue = "true", 
  matchIfMissing = true)
@Component
public class ApplicationRunnerTaskExecutor implements ApplicationRunner {
    // same as before
}
@ConditionalOnProperty(
  prefix = "command.line.runner", 
  value = "enabled", 
  havingValue = "true", 
  matchIfMissing = true)
@Component
public class CommandLineTaskExecutor implements CommandLineRunner {
    // same as before
}

Как мы видим, ПриложениеRunnerTaskExecutor и CommandLineTaskExecutor включены по умолчанию, и мы можем отключить их, если мы установите следующие свойства, чтобы ложные :

  • command.line.runner.enabled
  • application.runner.enabled

Итак, в нашем тесте, мы устанавливаем эти свойства для ложные и ни ПриложениеRunnerTaskExecutor ни CommandLineTaskExecutor бобы загружаются в контекст приложения :

@SpringBootTest(properties = { 
  "command.line.runner.enabled=false", 
  "application.runner.enabled=false" })
class RunApplicationWithTestPropertiesIntegrationTest {
    // same as before
}

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

Например, мы можем проверить, что Служба задач фасоль вводится правильно в CommandLineTaskExecutor, но мы все еще не хотим его запустить метод, который будет выполнен во время нашего теста.  Итак, давайте посмотрим последний раздел, который объясняет, как мы можем достичь этого.

6. Профилактика, не bootstrapping весь контейнер

Здесь мы опишем, как мы можем предотвратить CommandLineTaskExecutor и ПриложениеRunnerTaskExecutor бобы от исполнения, не bootstrapping весь контейнер приложения.

В предыдущих разделах мы использовали @SpringBootTest аннотация, и это привело к тому, что весь контейнер был загвеирован во время наших интеграционных тестов. @SpringBootTest включает в себя две мета-аннотации которые имеют отношение к этому последнему решению:

@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)

Ну, если нет необходимости bootstrap весь контейнер во время нашего теста, то не хочу использовать его @BootstrapWith .

Вместо этого, мы можем заменить его @ContextConfiguration :

@ContextConfiguration(classes = {ApplicationCommandLineRunnerApp.class},
  initializers = ConfigDataApplicationContextInitializer.class)

С @ContextConfiguration, мы определяем, как загрузить и настроить контекст приложения для интеграционных тестов. Установив КонтекстКонфигурация классы собственности, мы заявляем, что весенняя загрузка должна использовать ПриложениеCommandLineRunnerApp класса для загрузки контекста приложения. Определяя инициализатор, чтобы быть ConfigDataПрименениеКонтекстИнициализатор , приложение загружает свои свойства .

Нам все еще @ExtendWith (SpringExtension.class) так как это интегрирует Spring TestContext Framework в модель программирования JUnit 5.

В результате вышесказанного, контекст приложения Spring Boot загружает компоненты и свойства приложения без выполнения CommandLineTaskExecutor или ПриложениеRunnerTaskExecutor фасоль:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { ApplicationCommandLineRunnerApp.class }, 
  initializers = ConfigDataApplicationContextInitializer.class)
public class LoadSpringContextIntegrationTest {
    @SpyBean
    TaskService taskService;

    @SpyBean
    CommandLineRunner commandLineRunner;

    @SpyBean
    ApplicationRunner applicationRunner;

    @Test
    void whenContextLoads_thenRunnersDoNotRun() throws Exception {
        assertNotNull(taskService);
        assertNotNull(commandLineRunner);
        assertNotNull(applicationRunner);

        verify(taskService, times(0)).execute(any());
        verify(commandLineRunner, times(0)).run(any());
        verify(applicationRunner, times(0)).run(any());
    }
}

Кроме того, мы должны иметь в виду, что ConfigDataПрименениеКонтекстИнициализатор , когда он используется в одиночку, не обеспечивает поддержку @Value (“$”…”) инъекция. Если мы хотим поддержать его, мы должны настроить НедвижимостьРесурсПлейсхолдерКонфигуратор .

7. Заключение

В этой статье мы показали различные способы предотвращения исполнения ПриложениеРаннер и CommandLineRunner бобов во время интеграционных тестов Spring Boot.

Как всегда, код доступен более на GitHub .