带有@Configuration的内部静态类由弹簧扫描器为所有测试拾取。有什么问题?

时间:2017-09-21 12:03:40

标签: spring spring-boot junit

Spring从Test2中为Test1选取内部@Configuration。我需要在Test2中使用模拟的IService,但在Test1中需要一个真实的ServiceImpl。此外,我希望我的所有测试都有共同的TestConfiguration。但我总是在两个测试中都嘲笑IService。怎么了?

如何禁用内部配置以获取兄弟测试?

这是我的代码:

ServiceImpl.java:

@Service
public class SeriviveImpl implements IService {
}

TestConfiguration.java:

@Configuration
@ComponentScan
public class TestConfiguration {
   // empty
}

Test1.java:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfiguration.class})
public class Test1 {
    @Autowired
    private IService service;
}

Test2.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Test2.CustomConfiguration.class, TestConfiguration.class})
public class Test2 {
    @Autowired
    private IService service;

    @Configuration
    static class CustomConfiguration {
        @Bean
        IService service() {
            return mock(IService.class);
        }
    }
}

3 个答案:

答案 0 :(得分:2)

您可以从TestConfiguration @ComponentScan中过滤内部类:

@Configuration
@ComponentScan(excludeFilters = {
     @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
                           value = Test2.CustomConfiguration.class)
})
public class TestConfiguration {
   // empty
}

这将阻止它在Test1中被拾取。

编辑或者,如果您有许多内部配置,您可以创建自己的注释并从@ComponentScan中过滤所有这些带注释的类:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
public @interface InnerConfiguration {
}

然后在内部类而不是@Configuration上使用此注释:

@InnerConfiguration
    static class CustomConfiguration {
        @Bean
        IService service() {
            return mock(IService.class);
        }
    }

并按照以下步骤过滤掉组件扫描:

@Configuration
@ComponentScan(excludeFilters = {
     @ComponentScan.Filter(type = FilterType.ANNOTATION,
                           value = InnerConfiguration.class)
})
public class TestConfiguration {
   // empty
}

答案 1 :(得分:0)

您可以通过使用org.springframework.beans.factory.annotation.Qualifier注释明确选择所需的实现来实现这一点。以下是您的代码的外观:

...
@Service 
@Qualifier("impl")
public class SeriviveImpl implements IService {}
...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfiguration.class})
public class Test1 {
   @Autowired
   @Qualifier("impl")
   private IService service;
}
...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Test2.CustomConfiguration.class,TestConfiguration.class})
public class Test2 {
   @Autowired
   @Qualifer("mock")
   private IService service;

   @Configuration
   static class CustomConfiguration {
       @Bean
       @Qualifier("mock")
       IService service() { return mock(IService.class); }
   }
} 

答案 2 :(得分:0)

由于您在Test2.CustomConfiguration.class的{​​{1}}注释中明确使用了Test2,因此可以从@ContextConfiguration删除@Configuration注释,并且该注释不会被Test2.CustomConfiguration运行期间@ComponentScan

之所以有效,是因为:

  

使用带注释的方法为测试加载ApplicationContext   类(请参阅基于Java的容器配置),您可以进行注释   @ContextConfiguration测试类并配置这些类   属性,该数组包含对带注释的类的引用。

  

“带注释的类”一词可以指任何   以下:

     

用@Configuration注释的类。

     

一个组件(即带有@ Component,@ Service,   @Repository或其他构造型注释)。

     

一个与JSR-330兼容的类,并用javax.inject注释   注释。

     

任何其他包含@Bean方法的类。

请参见https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testcontext-ctx-management-javaconfig