【问题标题】:@ExceptionHandler not working with Spring MVC 3.1 unit test@ExceptionHandler 不适用于 Spring MVC 3.1 单元测试
【发布时间】:2012-07-23 20:14:51
【问题描述】:

通过在普通 servlet 上下文之外实例化对象,我几乎可以在 Spring MVC 控制器上进行所有单元测试。但我希望能够运行一些测试以确保我的对象序列化工作正常,正在生成标头等。

为了在 servlet 上下文中运行测试,我创建了一个修改过的上下文文件,以便不构造各种 bean,然后我使用 EasyMock 在我的测试用例中创建这些 bean 的模拟版本。然后我用这样的代码调用我的处理程序,并从 MockHttpServletResponse 中获取我需要的大部分内容。

我认为这是它的精髓:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:root-context.xml",
                                    "file:junit-servlet-context.xml" } )

public class HomeControllerConfigHandlerHttp {
@Autowired
private RequestMappingHandlerAdapter handlerAdapter;

@Autowired
private RequestMappingHandlerMapping handlerMapping;
    ... //miscellaneous setup
public void someTest() throws Exception
{
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setMethod("GET");
    request.setRequestURI("/config");
    request.addParameter("foo", "bar");
    request.addParameter("device", "oakmont");
    MockHttpServletResponse response = new MockHttpServletResponse();
    Object handler = handlerMapping.getHandler(request).getHandler();
    replay(dblient);
    expect(serviceClient.checkDevice("oakmont")).andReturn( true );
    serviceClient.destroy();
    replay(serviceClient);
    ModelAndView modelAndView = handlerAdapter.handle(request, response, handler);
    String content = new String( response.getContentAsByteArray() );
    Assert.assertEquals(content, "Expected configuration");
    String content_type = response.getHeader("Content-type");
    Assert.assertEquals( content_type, "text/plain");
    int status = response.getStatus();
    Assert.assertEquals(status,  200 );

这符合我的预期,但有一个问题。我用@ExceptionHandler 在我的控制器中做了很多错误处理。这是一种在任何处理程序中退出错误情况的简单方法,它为我提供了一种暴露错误的一致方式。

@ExceptionHandler 在正常的 servlet 部署中工作正常,但在这个单元测试模型中,当我抛出异常时它不会被调用。步入 Spring 代码对我来说有点挑战,我是新手,所以我很快就会迷路。但是,看起来在正常的 servlet 环境中,有一个异常处理程序来查找带注释的处理程序。在 SpringJUnit4ClassRunner 下运行时,异常的处理方式不同。

如果有办法解决这个问题,我愿意这样做。由于缺乏开拓精神,我已经避免使用 spring-test-mvc,但是如果有人告诉我它可以很好地解决这个问题,我会尝试一下。

我的 junit-servlet-context.xml 文件的内容与 Spring Template MVC 向导创建的 servlet-context.xml 文件几乎相同。唯一的区别是添加了一个排除过滤器,该过滤器用于防止 @Component 实例化创建我的控制器使用的几个单例。

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.cisco.onplus.home.dmz" >
<context:exclude-filter type="regex" expression=".*InitDatabase.*"/>
</context:component-scan>   
</beans:beans>

【问题讨论】:

  • 您能否展示一下您的 junit-servlet-context.xml 文件的内容,以及它与您的普通 Web 上下文文件的内容有何不同
  • junit-servlet-context.xml 文件与 Spring Template MVC 向导创建的 servlet-context.xml 文件相同,只有一个例外:添加了一个排除过滤器,它可以防止@Component 的实例化,它初始化了我的控制器使用的一些 bean。我已将其添加到主帖中。

标签: spring unit-testing spring-mvc spring-3


【解决方案1】:

恐怕您将不得不查看spring-test-mvc,原因是来自控制器的异常处理和使用ExceptionResolver 调用适当的@ExceptionHandler 是在DispatcherServlet 级别完成的,而不是HandlerAdapter。您的测试从HandlerAdapter 级别开始。

不过,我强烈推荐 spring-test-mvc,我已经使用了一段时间,并没有发现我的场景有任何问题 - http://biju-allandsundry.blogspot.com/2012/07/spring-mvc-integration-tests.html

使用 spring-test-mvc 对异常流的测试如下所示:

xmlConfigSetup("classpath:/META-INF/spring/web/webmvc-config.xml")
    .configureWebAppRootDir("src/main/webapp", false).build()
    .perform(get("/contexts/exception"))
    .andExpect(status().isOk())
    .andExpect(view().name("exceptionPage"));

【讨论】:

  • 谢谢,我有点担心问题出在 HandlerAdapter 上。我会看看我是否可以通过 spring-test-mvc 获得一些牵引力。这并不是说我看到它有什么大问题,但我只是不太高兴对仍在开发中的东西进行大笔投资。考虑到我对 Spring 还很陌生,使用文档较少的工具是一个很大的尝试。
【解决方案2】:

添加以下类以在上下文中加载 Dispatcher servlet:

public class MockWebApplicationContext extends AbstractContextLoader {

@Override
public ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) throws Exception {
    String[] locations = mergedContextConfiguration.getLocations();
    return loadContext(locations);
}

@Override
public ApplicationContext loadContext(String... locations) throws Exception {

    XmlWebApplicationContext webApplicationContext = new XmlWebApplicationContext();
    webApplicationContext.setConfigLocations(locations);
    webApplicationContext.setServletContext(new MockServletContext(new FileSystemResourceLoader() ) );

    ServletConfig config = new MockServletConfig();
    config.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, webApplicationContext);

    final DispatcherServlet servlet = new DispatcherServlet(webApplicationContext);

    webApplicationContext.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
            beanFactory.registerResolvableDependency(DispatcherServlet.class, servlet);
        }
    });

    webApplicationContext.refresh();
    servlet.init(config);

    return webApplicationContext;
}

@Override
protected String getResourceSuffix() {
    return ".xml";
}

}

一旦你完成了使用

@ContextConfiguration(locations = {"classpath:app-config.xml",loader = MockWebApplicationContext.class)

在测试类上使用 Autowired 注释加载 DispatcherServlet。处理它使用

servlet.service(request,response); 

现在它也应该处理异常流了。

不过它可能需要 3.1.2。

【讨论】:

  • 嘿@vivekd,我把这个 servlet.service(request,response); ??谢谢
猜你喜欢
  • 2013-05-16
  • 2011-07-03
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 2013-07-17
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
相关资源
最近更新 更多