【问题标题】:SpringBootTest - how to replace one bean in runtime configuration?SpringBootTest - 如何在运行时配置中替换一个 bean?
【发布时间】:2018-03-13 03:09:39
【问题描述】:

我正在为 Spring Boot 应用程序编写集成测试。只要我使用 100% 运行时配置进行测试,一切都会顺利进行。但是当我试图为 bean 提供一个自定义 bean 时,一切都会中断。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CombinedControllerIntegrationTest2 {

@TestConfiguration
static class ContextConfiguration {

    @Bean
    @Primary
    public SolrDocumentTypeMapRepository solrDocumentTypeMapRepository() {
        LOG.debug("SolrDocumentTypeMapRepository is being initialized.");

// etc.

上面的代码变体导致加载真实的运行时 SolrDocumentTypeMapRepository。我的测试类中的 ContextConfiguration 被忽略了。

如果我尝试在我的内部 ContextConfiguration 上使用 @Configuration 而不是 @TestConfiguration,则执行会落到另一个极端 - 它以

结束

org.springframework.context.ApplicationContextException:无法 由于缺少而启动 EmbeddedWebApplicationContext EmbeddedServletContainerFactory bean。

因为显然没有加载其余配置。

如果我尝试放

@ContextConfiguration(类 = {CombinedControllerIntegrationTest2.ContextConfiguration.class,GatewayApplication.class})

在我的主要测试类中,它以与 #1 相同的方式失败 - 即我的 ContextConfiguration 被忽略。

有什么想法吗?

附:我知道我可以使用@MockBean(这甚至在其他情况下也有效),但是在这里,因为在某些时候我依赖于主代码中的@PostConsruct 方法,@MockBeans 没用。

【问题讨论】:

标签: java spring testing spring-boot integration-testing


【解决方案1】:

使用@Mockean 模拟您的存储库。并在测试中添加行为:

@SpringBootTest
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)      
public abstract class IntegrationTest {

  @MockBean
  SolrDocumentTypeMapRepository solrDocumentTypeMapRepository;

  @Test
  public void mySuperTest(){ 
Mockito.when(solrDocumentTypeMapRepository.getById(Mockito.any())).thenReturn(someInstance);
Assert.assertEquals(solrDocumentTypeMapRepository.getById("someId"), someInstance);
}
}

【讨论】:

    【解决方案2】:

    使用一个 Bean 进行单元测试

    只需使用@RunWith(SpringRunner.class) 注释,它应该可以工作。您也可以使用@RunWith(SpringJUnit4ClassRunner.class)。两者都应该工作。

    请不要使用@SpringBootTest注解。它将连接整个应用程序。

    这是您更新的示例,

    @RunWith(SpringRunner.class)
    public class CombinedControllerIntegrationTest2 {
    
        @TestConfiguration
        static class ContextConfiguration {
    
            @Bean
            public SolrDocumentTypeMapRepository solrDocumentTypeMapRepository() {
                LOG.debug("SolrDocumentTypeMapRepository is being initialized.");
                return new SolrDocumentTypeMapRepository(...);
            }
        }
    
        @Autowired
        private SolrDocumentTypeMapRepository repository;
    
        @Test
        public void test() {
            assertNotNull(repository);
        }
    }
    

    使用替换的 Bean 进行集成测试

    • 创建一个新的测试 Spring Boot 应用程序。它应该排除负责创建SolrDocumentTypeMapRepository bean 的配置类(例如SolrConfiguration)。

      @SpringBootApplication
      @ComponentScan(basePackages = {
              "com.abc.pkg1",
              "com.abc.pk2"},
              excludeFilters = {
                      @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, 
                      value = SolrConfiguration.class)})
      public class TestApplication {
          public static void main(String[] args) throws Exception {
              SpringApplication.run(TestApplication.class, args);
          }
      }
      
    • 现在,在您的测试类中使用@ContextConfiguration 注解来添加TestApplication.classContextConfiguration.class。这会将您的应用程序与所有必需的 bean 连接起来,包括被替换的 bean。下图是更新后的测试类,

      @ActiveProfiles("test")
      @RunWith(SpringJUnit4ClassRunner.class)
      @SpringBootTest(webEnvironment = 
          SpringBootTest.WebEnvironment.RANDOM_PORT)
      @ContextConfiguration(classes = {TestApplication.class, 
          CombinedControllerIntegrationTest2.ContextConfiguration.class})
      public class CombinedControllerIntegrationTest2 {
      
          @TestConfiguration
          static class ContextConfiguration {
      
              @Bean
              public SolrDocumentTypeMapRepository solrDocumentTypeMapRepository() {
                  LOG.debug("SolrDocumentTypeMapRepository is being initialized.");
                  return new SolrDocumentTypeMapRepository(...);
              }
          }
      
          ...
      }
      

    【讨论】:

    • 谢谢,这就是我为 unit 测试所做的工作。此处不使用 @SpringBootTest 注释意味着我没有进行集成测试。我的应用程序还有许多其他我想使用的 bean。
    • @Alexander 更新了我的帖子,以表明您可以在集成测试中使用替换的 bean 以及其他应用程序 bean。
    • 谢谢! “TestApplication”方法奏效了。我仍然对“@TestConfiguration”注释感到失望。 Spring 文档让人相信它可以实现部分配置覆盖,但事实并非如此。
    • 是的,Spring 文档没有涵盖或明确角落用例。
    【解决方案3】:

    不要使用@Runwith(SpringJunit4Classrunner.class),而是使用@RunWith(SpringRunner.class)。这应该可以帮助您解决错误。

    【讨论】:

    猜你喜欢
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    • 2015-09-09
    • 2012-02-27
    • 2017-11-28
    • 1970-01-01
    相关资源
    最近更新 更多