Как исключить * классы автоконфигурации в тестах Spring Boot JUnit?

Я старался:

@RunWith(SpringJUnit4ClassRunner.class)
@EnableAutoConfiguration(exclude=CrshAutoConfiguration.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class LikeControllerTest {

Однако CRaSSHD все еще запускается. Хотя в настоящее время это не вредит тесту, я бы хотел отключить ненужные модули во время модульного тестирования, чтобы ускорить и избежать возможных конфликтов.

14 ответов

Решение

У меня был похожий случай использования, когда я хотел протестировать репозиторий, сконфигурированный Spring Boot, изолированно (в моем случае без автоконфигурации Spring Security, которая не прошла мой тест). @SpringApplicationConfiguration использования SpringApplicationContextLoader и это имеет JavaDoc заявляя

Может использоваться для тестирования не веб-функций (например, уровня репозитория) или запуска полностью настроенного встроенного контейнера сервлета.

Однако, как и вы, я не смог понять, как вы собираетесь настроить тест, чтобы тестировать только уровень репозитория, используя основную точку входа в конфигурацию, т.е. используя ваш подход @SpringApplicationConfiguration(classes = Application.class),

Мое решение состояло в том, чтобы создать совершенно новый контекст приложения, эксклюзивный для тестирования. Так что в src/test/java у меня есть два файла в подпакете под названием репо

  1. RepoIntegrationTest.java
  2. TestRepoConfig.java

где RepoIntegrationTest.java имеет

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestRepoConfig.class)
public class RepoIntegrationTest {

а также TestRepoConfig.java имеет

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class TestRepoConfig {

Это избавило меня от неприятностей, но было бы очень полезно, если бы кто-нибудь из команды Spring Boot мог предложить альтернативное рекомендуемое решение.

Еще один простой способ исключить классы автоконфигурации,

Добавьте ниже подобную конфигурацию к вашему файлу application.yml,

---
spring:
  profiles: test
  autoconfigure.exclude: org.springframework.boot.autoconfigure.session.SessionAutoConfiguration

Лучшие ответы не указывают на еще более простое и гибкое решение.

просто поместите

@TestPropertySource(properties=
{"spring.autoconfigure.exclude=comma.seperated.ClassNames,com.example.FooAutoConfiguration"})
@SpringBootTest
public class MySpringTest {...}

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

Спасибо @skirsch за поддержку в переходе от комментария к ответу.

У меня была похожая проблема, но я нашел другое решение, которое может помочь другим. Я использовал Spring Profiles для разделения классов тестирования и конфигурации приложения.

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

  2. В вашем тестовом классе установите профиль, соответствующий TestConfig, и включите его, используя аннотацию @ContextConfiguration.

Например:

конфигурация:

@Profile("test")
@Configuration
@EnableWebMvc
@ComponentScan(
    basePackages="your.base.package",
    excludeFilters = {
            @Filter(type = ASSIGNABLE_TYPE,
                    value = {
                            ExcludedAppConfig1.class,
                            ExcludedAppConfig2.class
            })
    })
public class TestConfig { ...}

тестовое задание:

@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
@WebAppConfiguration
public class SomeTest{ ... }

Я думаю, что с помощью @EnableAutoConfiguration аннотация на тестовом классе не будет работать, если вы используете @SpringApplicationConfiguration загрузить ваш Application учебный класс. Дело в том, что у вас уже есть @EnableAutoConfiguration аннотация в Application класс, который не исключает CrshAutoConfiguration,Spring использует эту аннотацию вместо той, что используется в вашем тестовом классе, для автоматической настройки ваших bean-компонентов.

Я думаю, что вам лучше всего использовать другой контекст приложения для ваших тестов и исключить CrshAutoConfiguration в этом классе.

Я сделал несколько тестов, и кажется, что @EnableAutoConfiguration на тестовом классе полностью игнорировать, если вы используете @SpringApplicationConfiguration аннотация и SpringJUnit4ClassRunner,

С новым @SpringBootTest аннотации, я взял этот ответ и изменил его, чтобы использовать профили с @SpringBootApplication класс конфигурации. @Profile аннотация необходима для того, чтобы этот класс выбирался только во время определенных интеграционных тестов, которые в этом нуждаются, поскольку другие конфигурации тестов выполняют сканирование различных компонентов.

Вот класс конфигурации:

@Profile("specific-profile")
@SpringBootApplication(scanBasePackages={"com.myco.package1", "com.myco.package2"})
public class SpecificTestConfig {

}

Затем тестовый класс ссылается на этот класс конфигурации:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { SpecificTestConfig.class })
@ActiveProfiles({"specific-profile"})
public class MyTest {

}
@SpringBootTest(classes = {Application.class}
              , webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
              , properties="spring.autoconfigure.exclude=com.xx.xx.AutoConfiguration"
               )

ссылка: https://github.com/spring-projects/spring-boot/issues/8579

Если проблема заключается в том, что ваша SpringBootApplication/Configuration, которую вы вводите, является компонентом, сканирующим пакет, в котором находятся ваши тестовые конфигурации, вы можете фактически удалить аннотацию @Configuration из тестовых конфигураций и по-прежнему использовать их в аннотациях @SpringBootTest. Например, если у вас есть класс Application, который является вашей основной конфигурацией, и класс TestConfiguration, который является конфигурацией для определенных, но не всех тестов, вы можете настроить свои классы следующим образом:

@Import(Application.class) //or the specific configurations you want
//(Optional) Other Annotations that will not trigger an autowire
public class TestConfiguration {
    //your custom test configuration
}

И тогда вы можете настроить свои тесты одним из двух способов:

  1. При штатной конфигурации:

    @SpringBootTest(classes = {Application.class}) //won't component scan your configuration because it doesn't have an autowire-able annotation
    //Other annotations here
    public class TestThatUsesNormalApplication {
        //my test code
    }
    
  2. С тестовой пользовательской конфигурацией теста:

    @SpringBootTest(classes = {TestConfiguration.class}) //this still works!
    //Other annotations here
    public class TestThatUsesCustomTestConfiguration {
        //my test code
    }
    

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

Вместо использования @SpringBootApplication используйте все три аннотации, которые в нем содержатся, и присвойте имя @Configuration.

@Configuration("myApp")
@EnableAutoConfiguration
@ComponentScan
public class MyApp { .. }

В вашем тестовом классе определите конфигурацию с точно таким же именем:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
// ugly hack how to exclude main configuration
@Configuration("myApp")
@SpringApplicationConfiguration(classes = MyTest.class)
public class MyTest { ... }

Это должно помочь. Было бы неплохо иметь более эффективный способ отключить автоматическое сканирование для аннотаций конфигурации...

Я боролся с подобной проблемой в течение одного дня... Мой сценарий:

У меня есть приложение SpringBoot, и я использую applicationContext.xml в scr/main/resources настроить все мои Spring Beans. Для тестирования (интеграционного тестирования) я использую другое applicationContext.xml в test/resources и все работает как я ожидал: Spring / SpringBoot переопределит applicationContext.xml из scr/main/resources и будет использовать тот для тестирования, который содержит компоненты, настроенные для тестирования.

Однако, только для одного UnitTest я хотел еще одну настройку для applicationContext.xml, используемого в тестировании, просто для этого теста я хотел использовать некоторые beck-компоненты mockito, чтобы я мог mock а также verifyи тут началась моя однодневная головная боль!

Проблема в том, что Spring / SpringBoot не переопределяет applicationContext.xml из scr/main/resources ТОЛЬКО ЕСЛИ файл из test/resources ИМЕТЕ ЖЕ ИМЯ. Я пытался часами использовать что-то вроде:

@RunWith(SpringJUnit4ClassRunner.class)
@OverrideAutoConfiguration(enabled=true)
@ContextConfiguration({"classpath:applicationContext-test.xml"})

это не сработало, Spring сначала загружал бины из applicationContext.xml в scr/main/resources

Мое решение основано на ответах здесь @myroch и @Stuart:

  1. Определите основную конфигурацию приложения:

    @Configuration @ImportResource({"classpath:applicationContext.xml"}) public class MainAppConfig { }

это используется в приложении

@SpringBootApplication
@Import(MainAppConfig.class)
public class SuppressionMain implements CommandLineRunner
  1. Определите TestConfiguration для Test, где вы хотите исключить основную конфигурацию

    @ComponentScan( basePackages = "com.mypackage", excludeFilters = { @ComponentScan.Filter(type = ASSIGNABLE_TYPE, value = {MainAppConfig.class}) }) @EnableAutoConfiguration открытый класс TestConfig { }

При этом для этого теста Spring не будет загружать applicationContext.xml и будет загружать только пользовательскую конфигурацию, специфичную для этого теста.

Я думаю, что лучшее решение для SpringBoot 2.0 - это использование профилей.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
public class ExcludeAutoConfigIntegrationTest {
    // ...
} 

spring.autoconfigure.exclude = org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration

в любом случае в следующей ссылке, чтобы решить эту проблему, дайте 6 разных вариантов.

Если у вас возникла эта проблема с Spring Boot 1.4.x и выше, вы можете использовать @OverrideAutoConfiguration(enabled=true) решить проблему.

Подобно тому, что спросили / ответили здесь /questions/20944465/kak-isklyuchit-otklyuchit-opredelennuyu-avtokonfiguratsiyu-v-spring-boot-140-dlya-datajpatest/20944485#20944485

Я также боролся с этим и нашел простой шаблон для выделения контекста теста после краткого чтения документов @ComponentScan.

/ **
* Типобезопасная альтернатива {@link #basePackages} для указания пакетов
* для сканирования аннотированных компонентов. Пакет каждого указанного класса будет проверен.
* Рассмотрите возможность создания специального класса или интерфейса no-op marker в каждом пакете.
* это не служит никакой другой цели, кроме ссылки на этот атрибут.
* /
Class<?>[] basePackageClasses() default {};

  1. Создать пакет для ваших весенних тестов, ("com.example.test"),
  2. Создайте интерфейс маркера в пакете в качестве спецификатора контекста.
  3. Предоставьте ссылку на интерфейс маркера в качестве параметра для basePackageClasses.

пример


IsolatedTest.java

package com.example.test;

@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan(basePackageClasses = {TestDomain.class})
@SpringApplicationConfiguration(classes = IsolatedTest.Config.class)
public class IsolatedTest {

     String expected = "Read the documentation on @ComponentScan";
     String actual = "Too lazy when I can just search on Stack Overflow.";

      @Test
      public void testSomething() throws Exception {
          assertEquals(expected, actual);
      }

      @ComponentScan(basePackageClasses = {TestDomain.class})
      public static class Config {
      public static void main(String[] args) {
          SpringApplication.run(Config.class, args);
      }
    }
}

...

TestDomain.java

package com.example.test;

public interface TestDomain {
//noop marker
}

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

      @ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {EmployeeService.class})
public class EmployeeLeavesTest { 

   @Autowired
   private EmployeeService employeeService;

}

В этом, например, только EmployeeServiceкласс будет доступен, а другие компоненты не будут загружены.

Другие вопросы по тегам