Тестирование приложения командной строки Spring Boot - PullRequest
0 голосов
/ 05 февраля 2020

Я хочу протестировать приложение командной строки Spring Boot. Я хотел бы посмеяться над некоторыми bean-компонентами (что я смог сделать, пометив @ContextConfiguration(classes = TestConfig.class) в верхней части моего тестового класса. В TestConfig.class я переопределяю bean-компоненты, которые я хотел бы высмеивать. Я хотел бы Spring Boot чтобы найти остальные компоненты. Кажется, это работает.

Проблема в том, что когда я запускаю тест, все приложение запускается как обычно (ie. Вызывается метод run()).

@Component
public class MyRunner implements CommandLineRunner {

    //fields

    @Autowired
    public MyRunner(Bean1 bean1, Bean2 bean2) {
        // constructor code
    }

    @Override
    public void run(String... args) throws Exception {
        // run method implementation
    }

Я пытался переопределить MyRunner @Bean и поместить его в TestConfig.class, но, похоже, это не работает. Я понимаю, что загружаю обычный контекст приложения , но это то, что я хотел бы сделать (я думаю?), поскольку я хотел бы повторно использовать все (или большинство) из @Component, которые я создал в своем Приложении, и только издеваться над небольшим подмножеством.

Есть предложения?

РЕДАКТИРОВАТЬ:

Приложение. java

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

Ответы [ 3 ]

0 голосов
/ 05 февраля 2020

Один из способов сделать это - использовать 2 класса с методом main, один из которых устанавливает «нормальный» контекст, а другой - «фиктивный» контекст:

Нормальный контекст приложения, использует обычный Application

@SpringBootApplication(scanBasePackages = "com.example.demo.api")
public class Application {

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

    @Bean
    public Foo foo() {
        return new Foo("I am not mocked");
    }

    @Bean
    public Bar bar() {
        return new Bar("this is never mocked");
    }
}

Добавить еще один Application класс, который переопределяет нормальный контекст с поддельным

@SpringBootApplication(scanBasePackageClasses = {MockApplication.class, Application.class})
@Component
public class MockApplication {

    public static void main(String[] args) {

        SpringApplication.run(MockApplication.class, args);
    }

    @Bean
    public Foo foo() {
        return new Foo("I am mocked");
    }
}

При запуске Application.main Foo будет "I я не издеваюсь ", когда вы запускаете MockApplication.main() это будет" Я издеваюсь "

0 голосов
/ 05 февраля 2020

Ответ был проще, чем я думал. Добавьте MockBean в

@TestConfiguration
public class TestConfig {

    @MockBean
    private MyRunner myRunner;

}

. Мы можем использовать @MockBean для добавления фиктивных объектов в контекст приложения Spring. Макет заменит любой существующий бин того же типа в контексте приложения.

Так что MyRunner.run() никогда не вызывается, но я все еще могу использовать все другие бины в моем приложении.

0 голосов
/ 05 февраля 2020

CommandLineRunners - это обычные bean-компоненты с одним исключением:

После загрузки контекста приложения Spring boot находит среди всех своих bean-компонентов, которые реализуют этот интерфейс, и автоматически вызывает их метод run.

Теперь я хотел бы попросить вас сделать следующее:

  1. Удалите ContextConfiguration из теста и поместите точку останова в конструктор MyRunner. Тест должен выглядеть так:
@RunWith(SpringRunner.class) // if you're on junit 4, adjust for junit 5 if you need
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MyTest {
   @Autowired
   private MyRunner myRunner;
   @Test
   public void testMe() {
     System.out.println("hello");
   }
}
Запустите тест и убедитесь, что myRunner загружен и его run метод называется Теперь смоделируйте этот класс с помощью аннотации MockBean:
@RunWith(SpringRunner.class) // if you're on junit 4, adjust for junit 5 if you need
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MyTest {

   @MockBean
   private MyRunner myRunner;
   @Test
   public void testMe() {
     System.out.println("hello");
   }
}

Запустить тест. Убедитесь, что метод run не запущен. Контекст вашего приложения теперь должен содержать фиктивную реализацию вашего компонента.

Если вышеприведенное работает, то проблема в аннотациях TestConfig и ContextConfiguration. В целом, когда вы запускаете без ContextConfiguration, вы предоставляете модулю весенней загрузки свободу для mimi c, когда контекст приложения запускается так, как будто это реальное приложение (с автоконфигурациями, разрешением свойств, рекурсивным сканированием bean-компонентов и т. Д.). Однако, если вы установите ContextConfiguration, тест весенней загрузки не будет работать так - он загружает только бины, которые вы указали в этой конфигурации. Нет автоконфигураций, например, не выполняется рекурсивное сканирование bean-компонентов.

Обновление

Основано на комментарии ОП:

Похоже MyRunner загружается при установке @ContextConfiguration из-за сканирования компонентов. Поскольку у вас есть аннотация @Component, размещенная в классе MyRunner, она может быть обнаружена загрузочным движком Spring.

На самом деле здесь существует «опасное» сочетание двух типов определений компонентов: 1. Объекты определяется с помощью @Bean в @Configuration аннотации 2. Компоненты, найденные во время сканирования компонентов.

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

@RunWith(SpringRunner.class)
@ContextConfiguration(YourConfig.class)
public class MyTest {
  ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...