MockMvc vs 端到端测试
MockMvc 基于 spring-test
模块中的 Servlet API mock 实现构建,不依赖于正在运行的容器。因此,与使用实际客户端和运行中服务器进行的完整的端到端集成测试相比,存在一些差异。
对此最简单的理解方式是,从一个空白的 MockHttpServletRequest
开始。你向其中添加什么,请求就会变成什么样。可能让你感到意外的是,默认情况下没有上下文路径;没有 jsessionid
cookie;没有转发、错误或异步分派;因此也没有实际的 JSP 渲染。相反,“转发”和“重定向”的 URL 被保存在 MockHttpServletResponse
中,可以通过期望进行断言。
这意味着,如果你使用 JSP,可以验证请求被转发到了哪个 JSP 页面,但不会渲染 HTML。换句话说,JSP 没有被调用。然而请注意,所有其他不依赖于转发的渲染技术,例如 Thymeleaf 和 Freemarker,都会像预期一样将 HTML 渲染到响应体中。通过 `@ResponseBody` 方法渲染 JSON、XML 和其他格式也是如此。
或者,你可以考虑使用 `@SpringBootTest` 的 Spring Boot 提供的完整端到端集成测试支持。请参阅Spring Boot 参考指南。
每种方法都有其优缺点。Spring MVC Test 中提供的选项是在经典单元测试到完整集成测试这一范围内的不同停靠点。可以肯定的是,Spring MVC Test 中的任何选项都不属于经典单元测试的范畴,但它们离经典单元测试更近一些。例如,你可以通过将模拟服务注入到控制器中来隔离 Web 层,在这种情况下,你仅通过 DispatcherServlet
测试 Web 层,但使用实际的 Spring 配置,就像你隔离测试数据访问层而不依赖于其上层一样。此外,你还可以使用独立设置,一次只关注一个控制器,并手动提供使其正常工作所需的配置。
使用 Spring MVC Test 的另一个重要区别在于,从概念上讲,这类测试是服务器端测试,因此你可以检查使用了哪个处理器,异常是否由 HandlerExceptionResolver
处理,模型的内容是什么,有哪些绑定错误,以及其他细节。这意味着编写期望更容易,因为服务器不是一个不透明的黑箱,这与通过实际 HTTP 客户端进行测试时不同。这通常是经典单元测试的一个优点:更容易编写、理解和调试,但它并不能取代完整集成测试的需求。同时,重要的是不要忽视响应是最重要的检查内容这一事实。简而言之,即使在同一个项目中,也有多种测试风格和策略的空间。