【问题标题】:@Import vs @ContextConfiguration for importing beans in unit tests用于在单元测试中导入 bean 的 @Import 与 @ContextConfiguration
【发布时间】:2017-11-05 22:36:34
【问题描述】:

我能够使用 SpringBoot 1.5.3 设置并成功运行三种不同的测试配置

方法#1。使用@Import注解导入Bean

@RunWith(SpringJUnit4ClassRunner.class)
@Import({MyBean.class})
public class MyBeanTest() {
    @Autowired
    private MyBean myBean;
}

方法#2。使用@ContextConfiguration注解导入Bean

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MyBean.class})
public class MyBeanTest() {
    @Autowired
    private MyBean myBean;
}

方法#3(带有内部类配置;基于the official blog post

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class MyBeanTest() {

    @Configuration
    static class ContextConfiguration {
        @Bean
        public MyBean myBean() {
            return new MyBean();
        }
    }

    @Autowired
    private MyBean myBean;

}

考虑到@Import注解文档

指示一个或多个 {@link Configuration @Configuration} 类以 导入。

事实上MyBean 不是一个配置类,而是一个带有@Component 注释的bean 类,看起来方法#1 是不正确的。

来自@ContextConfiguration 文档

{@code @ContextConfiguration} 定义类级元数据,即 用于确定如何加载和配置 {@link org.springframework.context.ApplicationContext ApplicationContext} 用于集成测试。

听起来它更适用于单元测试,但仍然应该加载一种配置。

方法#1 和#2 更短更简单。 方法#3 看起来是正确的方法。

我说的对吗?是否有其他标准为什么我应该使用方法 #3,例如性能或其他?

【问题讨论】:

  • MyBean 是否依赖于任何其他 bean?如果不是,我会像 MyBean myBean = new MyBean(); 那样实例化它
  • 是的,这取决于org.springframework.core.env.Environment

标签: spring unit-testing spring-boot


【解决方案1】:

这真的取决于您是使用 Spring Boot 提供的测试注释之一,还是从头开始构建上下文。 Spring Framework 中的核心支持要求您通过@ContextConfiguration 提供“根配置”。如果您使用的是 Spring Boot,它有它的own way of detecting the root context to use。默认情况下,它找到的第一个 @SpringBootConfiguration-annotated 类型。在典型的应用结构中,@SpringBootApplication 位于应用程序包的根目录中。

考虑到这一点,在该设置中使用 @ContextConfiguration 并不是一个好主意,因为它会禁用该查找,并且会做的不仅仅是“导入 bean”。

假设已经为你创建了上下文并且你想添加额外的bean,主要有两种方式:

如果您需要选择性地导入组件(在检测要使用的正确上下文的默认行为之上),那么@Import 绝对没问题。与此同时,@Import 的 Javadoc 被完善,提到导入组件绝对没问题,而且它并不特定于 @Configuration 类:

指示要导入的一个或多个组件类——通常是@Configuration 类。

所以,方法#1 是绝对正确的。

如果组件是测试的本地组件,并且您不需要与其他测试共享它,则可以使用内部 @TestConfiguration。这是also documented in the reference guide

【讨论】:

    【解决方案2】:

    如果您使用选项#3,您实际上不需要指定加载程序。 From the doc 除了文档中的示例之外,您还可以覆盖 env。如果您需要在环境中注入属性而不使用真实属性,请使用 @TestPropertySource

    @RunWith(SpringRunner.class)
    // ApplicationContext will be loaded from the
    // static nested Config class
    @ContextConfiguration
    @TestPropertySource(properties = { "timezone = GMT", "port: 4242" })
    public class OrderServiceTest {
    
        @Configuration
        static class Config {
    
            // this bean will be injected into the OrderServiceTest class
            @Bean
            public OrderService orderService() {
                OrderService orderService = new OrderServiceImpl();
                // set properties, etc.
                return orderService;
            }
        }
    
        @Autowired
        private OrderService orderService;
    
        @Test
        public void testOrderService() {
            // test the orderService
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2019-11-04
      • 2018-06-28
      • 2015-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-06
      • 2023-01-26
      相关资源
      最近更新 更多