【问题标题】:Preventing a @EnableWebMvc-annotated class from being picked up by @ComponentScan防止 @ComponentScan 拾取带有 @EnableWebMvc 注释的类
【发布时间】:2014-02-03 12:34:10
【问题描述】:

我有以下测试类:

@ActiveProfiles({ "DataTC", "test" })
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {BaseTestConfiguration.class, DataTestConfiguration.class, JpaConfiguration.class, PropertyPlaceholderConfiguration.class })
public class RegularDayToTimeSlotsTest {

    private static int NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK = 25;

    @Autowired
    private AdvertisementService advertisementService;

    @Test
    public void shouldNotContainSaturdayNorSunday() {
        Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
        assertThat(regularDayToTimeSlots).onProperty("day").excludes(Day.SATURDAY, Day.SUNDAY);
    }

    @Test
    public void shouldNotContainEveningNorNighttime() {
        Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
        assertThat(regularDayToTimeSlots).onProperty("timeSlot").excludes(TimeSlot.EVENING, TimeSlot.NIGHTTIME);
    }

    @Test
    public void shouldContainCorrectNumberOfDayToTimeSlots() {
        Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
        assertThat(regularDayToTimeSlots).hasSize(NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK);
    }
}

这是一个不需要任何 ServletContext 的集成测试。这是 BaseTestConfiguration 类:

@Configuration
@ComponentScan(basePackages = { "com.bignibou" }, excludeFilters = { @Filter(type = FilterType.CUSTOM, value = RooRegexFilter.class),
        @Filter(type = FilterType.ANNOTATION, value = Controller.class), @Filter(type = FilterType.ANNOTATION, value = ControllerAdvice.class),
        @Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class) })
public class BaseTestConfiguration {

}

这只是一个 java 配置类,旨在确保我的所有应用程序 bean 都被正确实例化和连接,但没有考虑使用 @EnableWebMvc 注释的类,因为我不需要 Servlet 上下文用于此集成测试。

不幸的是,无论我如何尝试排除 Web/Mvc 配置类,它都不起作用,并且使用 @EnableWebMvc 注释的 @Configuration 类也被选中。

我得到了这个例外:

Caused by: java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
    at org.springframework.util.Assert.notNull(Assert.java:112)
    at org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer.<init>(DefaultServletHandlerConfigurer.java:54)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping(WebMvcConfigurationSupport.java:329)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$d1263fa1.CGLIB$defaultServletHandlerMapping$22(<generated>)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$d1263fa1$$FastClassByCGLIB$$e0423f09.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:326)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$d1263fa1.defaultServletHandlerMapping(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
    ... 43 more

有人可以帮忙吗?

【问题讨论】:

    标签: spring spring-test


    【解决方案1】:

    实际上有一种更简洁的方式来配置此类集成测试。

    答案在于正确的关注点分离,不仅在类级别,而且在包级别。

    始终建议实现类和配置类都驻留在允许适当分离关注点的包层次结构中。特别是对于 Web 应用程序,强烈建议确保 Web 组件和 Web 配置驻留在专用的“Web”包中。例如,您可以考虑类似于以下的包层次结构:

    • com.example.domain
    • com.example.service
    • com.example.repository
    • com.example.web

    使用这样的层次结构,您可以通过包含仅与当前应用程序或测试场景相关的那些基本包来简化组件扫描配置。通过这样做,通常不需要对您不想要的东西使用 exclusion 过滤器。相反,只需指定您确实想要的包。

    顺便说一句,将"com.bignibou" 指定为基本包实际上是最糟糕的做法,因为它包罗万象。

    因此,请尝试使用明确的包包含(而不是排除 @Controller@ControllerAdvice 等),看看这是否不会让您的生活更轻松。 ;)

    问候,

    山姆

    【讨论】:

    • 非常感谢 Sam 提供的有用建议。
    • 对不起,我忘了提到另一个问题,即需要指定所有 @Configuration-annoatated 类:@ContextConfiguration(classes = { BaseTestConfiguration.class, DataTestConfiguration.class, JpaConfiguration.class, RestConfiguration.class, DevMailConfiguration.class, PropertyPlaceholderConfiguration.class, ThymeleafConfiguration.class })。如何避免指定所有 @Configuration 类的繁琐?
    • 你为什么不为你的集成测试创建一个 @Configuration 类(例如,IntegrationTestConfig),用 @ComponentScan 注释该类(配置以便它找到你的配置类需要),然后只需在您的集成测试类中指定@ContextConfiguration(classes = IntegrationTestConfig.class)
    【解决方案2】:

    我能够让它工作,但以非常污染的测试课程为代价。这里是:

    @ActiveProfiles({ "DataTC", "test", "dev", "default" })
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = { BaseTestConfiguration.class, DataTestConfiguration.class, JpaConfiguration.class, RestConfiguration.class, DevMailConfiguration.class,
            PropertyPlaceholderConfiguration.class, ThymeleafConfiguration.class })
    public class RegularDayToTimeSlotsTest {
    ...
    

    这是 BaseTestConfiguration 类:

    @Configuration
    @ComponentScan(basePackages = { "com.bignibou" }, excludeFilters = { @Filter(type = FilterType.CUSTOM, value = RooRegexFilter.class),
            @Filter(type = FilterType.ANNOTATION, value = Controller.class), @Filter(type = FilterType.ANNOTATION, value = ControllerAdvice.class),
            @Filter(type = FilterType.ANNOTATION, value = Configuration.class) })
    @ImportResource(value="classpath*:META-INF/spring/applicationContext-security.xml")
    public class BaseTestConfiguration {
    ...
    

    必须有一种更简洁的方式来实施和运行集成测试...欢迎任何建议...

    【讨论】:

      猜你喜欢
      • 2017-03-17
      • 2017-06-25
      • 1970-01-01
      • 2016-06-02
      • 2019-09-16
      • 2014-08-02
      • 2020-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多