![](/img/trans.png)
[英]Testing Spring MVC @ExceptionHandler method with Spring MVC Test
[英]@ExceptionHandler not working with Spring MVC 3.1 unit test
通过在普通的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文件相同。 唯一的区别是添加了一个exclude-filter,用于防止@Component的实例化,该@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>
添加以下类以在上下文中加载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-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"));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.