通过在普通 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>