SpringBootTest - 如何在运行时配置中替换一个bean?

时间:2017-10-02 02:43:24

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

我正在为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(classes =   {CombinedControllerIntegrationTest2.ContextConfiguration.class,GatewayApplication.class})

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

有什么想法吗?

P.S。我知道我可以使用@MockBean(这甚至适用于其他情况),但是在这里,因为在某些时候我依赖于主代码中的@PostConsruct方法,所以@MockBeans没用。

3 个答案:

答案 0 :(得分:5)

使用One 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应用程序。它应该排除负责创建SolrConfiguration bean的配置类(例如SolrDocumentTypeMapRepository)。

    @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(...);
            }
        }
    
        ...
    }
    

答案 1 :(得分:0)

使用@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 :(得分:-2)

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