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 客户端测试它时那样。这通常是经典单元测试的优势:它更容易编写、推理和调试,但不能替代对完整集成测试的需求。同时,重要的是不要忽视响应是最重要的事情。简而言之,即使在同一个项目中,也有空间容纳多种测试风格和策略。