spring之@ExceptionHandler 不适用于 Spring MVC 3.1 单元测试
通过在正常 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。
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。