【问题标题】:Why unit testing with Spring 3.1 WebMvcConfig fails?为什么使用 Spring 3.1 WebMvcConfig 进行单元测试会失败?
【发布时间】:2012-07-03 12:51:43
【问题描述】:

从 Spring 3.1 开始,由于 @Enable* 注释,我们可以更轻松地使用 JavaConfig。

所以我做了一个 WebConfig 来设置 WebMvc 配置,并尝试测试它。但是,如果我使用 WebConfig 扩展 WebMvcConfigurerAdapter 或 WebMvcConfigurationSupport,则单元测试会因缺少 ServletContext 而失败。代码和消息如下所示。

WebConfig.java

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport {}

Test.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=WebConfig.class)
public class TestFail {
    @Test
    public void test() {}
}

留言

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
...
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:253)
    at com.zum.news.comments.web.WebConfig$$EnhancerByCGLIB$$8bbfcca1.CGLIB$defaultServletHandlerMapping$10(<generated>)
    at com.zum.news.comments.web.WebConfig$$EnhancerByCGLIB$$8bbfcca1$$FastClassByCGLIB$$19b86ad0.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:215)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:280)
    at com.zum.news.comments.web.WebConfig$$EnhancerByCGLIB$$8bbfcca1.defaultServletHandlerMapping(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:149)
    ... 41 more

如何正确地对 WebConfig 进行单元测试?

编辑

正如 Garcia 所说,这个错误已在 Spring 3.2.0.RC1 中修复。

只需在测试类中添加@WebAppConfiguration注解即可。

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes=WebConfig.class)
public class TestFail {
    @Test
    public void test() {}
}

【问题讨论】:

  • 我不明白这个问题的票数怎么这么少。我想有些人试图用 Spring 3.1 的细节进行集成测试......
  • 这个问题正是我要找的,答案包含在“编辑”部分

标签: java spring spring-3


【解决方案1】:

如果@EnableWebMvc 注释需要ServletContext,那么我建议将您的配置拆分为bean 定义,这些定义将用于单元测试和应用程序和框架使用的其他配置。在这种情况下,应用程序将同时导入配置,而单元测试将只导入一个。

BeansConfig.java:

@Configuration
public class BeansConfig {
    @Bean
    MyBean myBean() {
        return new MyBean()
    }
}

WebConfig.java:

@Configuration
@EnableWebMvc
@Import(BeansConfig.class)
public class WebConfig extends WebMvcConfigurationSupport {}

TestFail.java:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=BeansConfig.class)
public class TestFail {
    @Test
    public void test() {}
}

【讨论】:

  • 其实,这就是我现在正在做的。我想知道为什么单元测试失败。在 Spring 3.0 中配置 XML 就可以了。
【解决方案2】:

我的另一个建议是使用spring-test-mvc,它在内部创建了一个模拟 servlet 上下文,以便控制器测试工作。

如果您想继续使用您的方法,您可能必须创建自己的 Spring Context 加载器,该加载器另外初始化一个 Mock servlet 上下文 - 遵循以下原则: http://tedyoung.me/2011/02/14/spring-mvc-integration-testing-controllers/, 来自Spring-test-mvc source

【讨论】:

    【解决方案3】:

    Spring 3.1有一个bug,你可以在这两个问题中找到答案:

    如果您找到 Spring 3.1 的解决方法,请告诉我们,如果没有,我们必须等到 3.2 发布。我不得不说我刚刚用 Spring 3.2.0.M2 尝试过,但它仍然不适合我。

    【讨论】:

    • 3.2.0.RC1 已发布,该错误已修复。它应该也可以在 3.2.0.M2 上运行,只要您使用 @WebAppConfiguration 注释您的测试类。
    【解决方案4】:

    正如 Guido 之前提到的,这已在 3.2 中解决。以下是如何利用新测试改进的详细信息。为确保为您的测试加载 servlet 上下文,您需要使用 @WebAppConfiguration 注释您的测试并将AnnotationConfigWebContextLoader 定义为您的上下文加载器,如下所示:

    @RunWith(SpringJUnit4ClassRunner.class)    
    @WebAppConfiguration
    @ContextConfiguration(
        classes = MyWebConfig.class, 
        loader = AnnotationConfigWebContextLoader.class)
    public class MyTest {
        //...
    }
    

    【讨论】:

    • 您能否解释一下在这些测试用例中如何加载应用程序 spring 上下文。我很欣赏 MyWebConfig 类替换了用于初始化 Web 应用程序的 servlet-context.xml 文件,但是如果我们的 Controller 依赖于其他要注入的 bean,这是如何完成的。在其他示例中,将“location=classparth=context.xml”传递给 ContextConfiguration - 在上面的示例中这仍然可能吗?
    • @Configuration 类中。这定义了应扫描哪些类路径以查找注释为 @Component@Controller@Service 等的 bean。它还可以使用 Import 注释来导入 XML 上下文。如果您愿意,可以专门为您的测试创建 @Configuration 类。
    • 谢谢。在我们真正的网络应用程序中,我在 web.xml 文件中有一个 ContextLoaderListener,它加载了 contextConfigLocation='/WEB-INF/applicationContext.xml'。对于我的测试用例,我认为您建议我将 Import 语句添加到我的 WebAppConfig 类中,但这并不意味着如果真正的 webapp 加载了两次上下文。我可能预计测试类代码会做一些事情来加载 applicationContext.xml 而不是读取配置类。
    • 您可以从 web.xml 中删除加载程序。如果您花一点时间用@configuration 类替换它,甚至可以完全删除 web.xml。或者,在您的测试类中创建一个配置,您正在运行的应用程序不使用该配置。
    猜你喜欢
    • 1970-01-01
    • 2022-06-29
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多