【问题标题】:How to exclude *AutoConfiguration classes in Spring Boot JUnit tests?如何在 Spring Boot JUnit 测试中排除 *AutoConfiguration 类?
【发布时间】:2014-12-29 03:42:50
【问题描述】:

我试过了:

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

但是,CRaSSHD 仍然启动。虽然目前它不会损害测试,但我想在单元测试期间禁用不必要的模块以加快速度并避免潜在的冲突。

【问题讨论】:

  • CRaSSHD 应该是什么?
  • 考虑到 Jean-Philippe Bond 的回答(解释 @SpringApplicationConfiguration 阻止 @EnableAutoConfiguration 生效),值得注意的是,在像 @DataJpaTest 这样的测试切片复合注释中,我们看到它们使用@OverrideAutoConfiguration(enabled=false) 的组合广泛禁用自动配置,使用@ImportAutoConfiguration(classes...) 重新打开特定配置。随着新的自动配置元素被添加到应用程序中,这些将继续工作。

标签: java spring junit spring-boot


【解决方案1】:

另一种排除自动配置类的简单方法,

将以下类似配置添加到您的 application.yml 文件中,

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

【讨论】:

  • 感谢您提供这个非常简单有效的解决方案。你节省了我的时间:)
  • 要向属性spring.autoconfigure.exclude添加多个自动配置类,只需将所有类名称用,分隔即可
  • @Kane 我发现在 *Test 类上指定 @TestPropertySource(properties= {"spring.autoconfigure.exclude=comma.seperated.ClassNames,com.example.FooAutoConfiguration"}) 更容易。无需为不需要的配置的每个排列定义配置文件。
  • @coderatchet 你是真正的 MVP。请提供此作为答案,这是最有帮助的。
【解决方案2】:

热门答案并不指向更简单、更灵活的解决方案。

只需放置一个

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

您的测试类上方的注释。这意味着其他测试不受当前测试的特殊情况的影响。如果某个配置影响了您的大部分测试,那么请考虑按​​照当前最佳答案的建议使用弹簧配置文件。

感谢 @skirsch 鼓励我将其从评论升级为答案。

【讨论】:

  • 我需要在我的测试用例中排除一​​个配置类(不是自动配置的)。这是一个用@Configuration 注释的自定义类,我需要跳过在我的测试用例中加载它。当我尝试上面的spring.autoconfigure.exclude 参数时,我收到一个错误,指出该类不是自动配置的。有什么帮助吗?
  • 这对我来说非常有效,但我确实需要使用配置文件来防止创建我试图避免的 Cassandra 存储库 bean。
【解决方案3】:

我有一个类似的用例,我想单独测试一个 Spring Boot 配置的存储库(在我的情况下,没有 Spring Security 自动配置,它没有通过我的测试)。 @SpringApplicationConfiguration 使用 SpringApplicationContextLoader 并且有一个 JavaDoc 声明

可用于测试非 Web 功能(如存储库层)或 启动一个完全配置的嵌入式 servlet 容器。

但是,和您一样,我无法弄清楚您打算如何将测试配置为仅使用主配置入口点测试存储库层,即使用您的 @SpringApplicationConfiguration(classes = Application.class) 方法。

我的解决方案是创建一个专门用于测试的全新应用程序上下文。所以在 src/test/java 我在一个名为 repo 的子包中有两个文件

  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 团队的任何人都可以提供替代推荐解决方案,那将非常有用

【讨论】:

  • 这对我来说是正确的解决方案。您需要稍微不同的配置进行测试,然后定义一个。也许您不喜欢使用 \@SprintBootApplication 注释测试配置。但考虑到这只是 \@Configuration \@ComponentScan \@EnableComponentScan 的快捷方式。这些在测试配置上看起来还不错。
  • 您的ApplicationTestRepoConfig 类驻留在哪些包中?因为我有类似的问题,但这个解决方案对我不起作用。排除的配置类仍然包含在内。我的两个@SpringBootApplication 类都位于应用程序的根包中(即com.company.app)。
  • 在我的情况下,应用程序将在 com.company.app 和 TestRepoConfig 在 com.company.app.repo
【解决方案4】:

我遇到了类似的问题,但我找到了一个可能对其他人有所帮助的不同解决方案。我使用 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{ ... }

【讨论】:

    【解决方案5】:

    如果您使用@SpringApplicationConfiguration 加载Application 类,我认为在测试类上使用@EnableAutoConfiguration 注释将不起作用。问题是您在 Application 类中已经有一个 @EnableAutoConfiguration 注释,它不排除 CrshAutoConfiguration.Spring 使用该注释而不是您的测试类上的注释来执行您的 bean 的自动配置。

    我认为您最好的选择是为您的测试使用不同的应用程序上下文,并在该类中排除 CrshAutoConfiguration

    我做了一些测试,如果您使用@SpringApplicationConfiguration 注释和SpringJUnit4ClassRunner,测试类上的@EnableAutoConfiguration 似乎完全被忽略了。

    【讨论】:

    • 如何构建一个包含多个不同应用程序的项目? Spring Boot 不会扫描其他应用程序吗?对于这种情况,推荐的最佳做法是什么……?我认为这是常见的用法,测试配置与应用程序配置有些不同。
    【解决方案6】:

    使用新的@SpringBootTest 注释,我采用this answer 并将其修改为使用带有@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 {
    
    }
    

    【讨论】:

    • 这对你真的有用吗?我只为@SpringBootApplication 的scanBasePackages 定义了1 个包,但是当我运行我的测试时,它仍在从另一个包初始化类。其余代码相同。我正在使用 spring boot 1.4.0.RELEASE
    • 它仍然会使用@SpringBootApplication 进入我的主配置类进行生产。我在那里添加了配置文件规范并将我的配置包添加到 scanBasePackages,现在它正在工作!
    【解决方案7】:
    @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

    【讨论】:

      【解决方案8】:

      如果问题是你引入的 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
        }
        

      【讨论】:

        【解决方案9】:

        遇到了同样的问题,在测试期间无法排除主要的 Spring Boot 类。使用以下方法解决它。

        不使用@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 { ... }
        

        这应该会有所帮助。如果有一些更好的方法来禁用自动扫描配置注释会很高兴...

        【讨论】:

          【解决方案10】:

          我已经为类似的问题苦苦挣扎了一天……我的情景:

          我有一个 SpringBoot 应用程序,我使用 scr/main/resources 中的 applicationContext.xml 来配置我所有的 Spring Bean。 对于测试(集成测试),我在 test/resources 中使用了另一个 applicationContext.xml 并且事情按我预期的那样工作:Spring/SpringBoot 将覆盖 scr/main/resources 中的 applicationContext.xml并将使用包含配置用于测试的 bean 的测试。

          但是,对于一个 UnitTest,我想要对测试中使用的 applicationContext.xml 进行另一种自定义,只是为了这个测试,我想使用一些模拟 bean,所以我可以 mock 和 @ 987654325@,从此开始了我一天的头痛!

          问题在于 Spring/SpringBoot 不会覆盖来自 scr/main/resourcesapplicationContext.xml,仅当来自 test/resources 的文件具有相同的名称时。 我尝试了几个小时来使用类似的东西:

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

          它不起作用,Spring首先从scr/main/resources中的applicationContext.xml加载bean

          我的解决方案基于@myroch 和@Stuart 的答案:

          1. 定义应用的主要配置:

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

          这是在应用程序中使用的

          @SpringBootApplication
          @Import(MainAppConfig.class)
          public class SuppressionMain implements CommandLineRunner
          
          1. 为要排除主要配置的测试定义一个 TestConfiguration

            @ComponentScan( basePackages = "com.mypackage", 排除过滤器 = { @ComponentScan.Filter(type = ASSIGNABLE_TYPE, 值 = {MainAppConfig.class}) }) @EnableAutoConfiguration 公共类TestConfig { }

          通过这样做,对于这个测试,Spring 将不会加载 applicationContext.xml 并且只会加载特定于这个测试的自定义配置。

          【讨论】:

            【解决方案11】:

            在粗略阅读 @ComponentScan 文档后,我发现了一个简单的模式来隔离测试上下文。

            /**
            * 用于指定包的 {@link #basePackages} 的类型安全替代方案
            * 扫描带注释的组件。将扫描指定的每个类的包。
            * 考虑在每个包中创建一个特殊的无操作标记类或接口
            * 除了被此属性引用之外没有其他用途。
            */
            Class<?>[] basePackageClasses() default {};

            1. 为您的 Spring 测试创建一个包,("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
            }
            

            【讨论】:

            • 虽然basePackageClasses= 可用于控制我们的应用程序的哪些配置,但它对Spring Boot自己的配置没有影响。
            • 您是否注意到我正在运行一个单独的实例进行测试? public static class Config{} ...这是一个孤立的实例...甚至不是同一个应用...
            【解决方案12】:

            如果您在使用 Spring Boot 1.4.x 及更高版本时遇到此问题,您也许可以使用 @OverrideAutoConfiguration(enabled=true) 来解决问题。

            类似于https://stackoverflow.com/a/39253304/1410035 此处提出/回答的问题

            【讨论】:

              【解决方案13】:

              我认为目前 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

              无论如何,下面link 给出了 6 种不同的替代方案来解决这个问题。

              【讨论】:

              • Profiles 在 Spring Boot 2 中并不是新事物。它自 Spring 3 (2011) 左右就已经存在。它与排除不使用配置文件的自动配置无关,这几乎是所有配置文件。
              【解决方案14】:

              因此,要禁用自动加载测试的所有 Bean,测试类可以明确提及所需的依赖项。 这可以使用ContextConfiguration 注释来完成。 例如,

              @ExtendWith(SpringExtension.class)
              @ContextConfiguration(classes = {EmployeeService.class})
              public class EmployeeLeavesTest { 
              
                 @Autowired
                 private EmployeeService employeeService;
              
              }
              

              在这个例子中,只有EmployeeService 类可用,其他bean 不会被加载。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-01-24
                • 2017-06-06
                • 1970-01-01
                • 2020-05-14
                • 2019-10-26
                • 2018-11-02
                • 2022-01-08
                • 2016-11-23
                相关资源
                最近更新 更多