spring之@ExceptionHandler 不适用于 Spring MVC 3.1 单元测试

mengfanrong 阅读:14 2024-11-01 17:39:52 评论:0

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

为了在 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 在我的 Controller 中进行了很多错误处理。这是一种退出任何处理程序中的错误情况的简单方法,它为我提供了一种暴露错误的一致方式。

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

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

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

<?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> 

请您参考如下方法:

添加以下类以在上下文中加载 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。


标签:Spring
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号