对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

MockMvc 与端到端测试

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

理解这一点最简单的方式是从一个空白的 MockHttpServletRequest 开始。 你向其中添加的内容就构成了该请求。可能会让你感到意外的是:默认情况下没有上下文路径(context path); 没有 jsessionid cookie;没有转发(forwarding)、错误(error)或异步(async)分派; 因此,也不会实际渲染 JSP 页面。取而代之的是,“转发”和“重定向”的 URL 会被保存在 MockHttpServletResponse 中,你可以通过断言来验证它们。spring-doc.cadn.net.cn

这意味着,如果你使用 JSP,你可以验证请求被转发到的 JSP 页面,但不会渲染任何 HTML。换句话说,JSP 并不会被实际调用。然而,请注意,所有其他不依赖于转发的渲染技术(例如 Thymeleaf 和 Freemarker)会如预期那样将 HTML 渲染到响应体中。通过 @ResponseBody 方法渲染 JSON、XML 以及其他格式的情况也是如此。spring-doc.cadn.net.cn

或者,您可以考虑使用 Spring Boot 提供的完整端到端集成测试支持,即 @SpringBootTest。请参阅Spring Boot 参考指南spring-doc.cadn.net.cn

每种方法都有其优缺点。Spring MVC Test 提供的选项在经典单元测试到完整集成测试的尺度上处于不同的位置。可以肯定的是,Spring MVC Test 中的任何选项都不属于经典单元测试的范畴,但它们更接近于单元测试。例如,你可以通过向控制器注入模拟的服务来隔离 Web 层,此时你仅通过 DispatcherServlet 对 Web 层进行测试,但使用的是真实的 Spring 配置,就像你在隔离数据访问层时将其与上层解耦进行测试一样。此外,你还可以使用独立设置(stand-alone setup),一次专注于一个控制器,并手动提供使其正常工作所需的配置。spring-doc.cadn.net.cn

使用 Spring MVC Test 时另一个重要的区别在于,从概念上讲,这类测试属于服务器端测试,因此你可以检查使用了哪个处理器(handler)、异常是否通过 HandlerExceptionResolver 被处理、模型(model)的内容是什么、存在哪些绑定错误(binding errors)以及其他细节。这意味着编写断言会更加容易,因为在通过实际的 HTTP 客户端进行测试时,服务器就像一个黑盒,而在这里则不是。这通常是经典单元测试的一个优势:更容易编写、理解和调试,但它并不能取代完整的集成测试的必要性。同时,我们也不应忽视这样一个事实:响应(response)始终是最重要的验证内容。简而言之,即使在同一个项目中,也存在多种测试风格和策略的空间。spring-doc.cadn.net.cn