MockMvc 与端到端集成测试

MockMvc 是基于 spring-test 模块中的 Servlet API 模拟实现构建的,它不依赖于运行中的容器。因此,与使用实际客户端和正在运行的实时服务器进行完整的端到端集成测试相比,存在一些差异。

最简单的理解方式是,从一个空白的 MockHttpServletRequest 开始。你向其中添加的任何内容都将构成该请求。可能会让你感到惊讶的是,默认情况下没有上下文路径;没有 jsessionid cookie;没有转发、错误或异步调度;因此,也没有实际的 JSP 渲染。相反,“转发”和“重定向”的 URL 会保存在 MockHttpServletResponse 中,并且可以通过断言进行验证。

这意味着,如果你使用 JSP,你可以验证请求被转发到的 JSP 页面,但不会渲染任何 HTML。换句话说,JSP 不会被调用。但是请注意,所有其他不依赖于转发的渲染技术,例如 Thymeleaf 和 Freemarker,都会按预期将 HTML 渲染到响应体中。通过 @ResponseBody 方法渲染 JSON、XML 和其他格式也是如此。

或者,你可以考虑使用 Spring Boot 提供的 @SpringBootTest 进行完整的端到端集成测试支持。请参阅 Spring Boot 参考指南

每种方法都有其优缺点。Spring MVC Test 中提供的选项介于经典单元测试和完整集成测试之间。可以肯定的是,Spring MVC Test 中的任何选项都不属于经典单元测试的范畴,但它们更接近于经典单元测试。例如,你可以通过将模拟服务注入控制器来隔离 Web 层,在这种情况下,你仅通过 DispatcherServlet 测试 Web 层,但使用实际的 Spring 配置,就像你可能隔离数据访问层并与其上层进行测试一样。此外,你可以使用独立设置,一次只关注一个控制器,并手动提供使其工作所需的配置。

使用 Spring MVC Test 时的另一个重要区别是,从概念上讲,此类测试是服务器端测试,因此你可以检查使用了哪个处理器,异常是否由 HandlerExceptionResolver 处理,模型的内容是什么,存在哪些绑定错误以及其他详细信息。这意味着更容易编写期望,因为服务器不是一个不透明的盒子,不像通过实际的 HTTP 客户端进行测试时那样。这通常是经典单元测试的优势:它更容易编写、推理和调试,但不能取代对完整集成测试的需求。同时,重要的是不要忽略响应是最重要的检查内容这一事实。简而言之,即使在同一个项目中,也有多种测试风格和策略的空间。