单元测试

依赖注入应该使您的代码对容器的依赖性降低,而不是像传统的 J2EE/Java EE 开发那样。构成应用程序的 POJO 应该在 JUnit 或 TestNG 测试中可测试,使用new运算符实例化对象,无需 Spring 或任何其他容器。您可以使用模拟对象(结合其他有价值的测试技术)来隔离测试您的代码。如果您遵循 Spring 的架构建议,则代码库产生的干净分层和组件化将促进更轻松的单元测试。例如,您可以通过存根或模拟 DAO 或存储库接口来测试服务层对象,而无需在运行单元测试时访问持久数据。

真正的单元测试通常运行速度非常快,因为没有运行时基础架构需要设置。将真正的单元测试作为开发方法的一部分进行强调可以提高您的生产力。您可能不需要测试章节的这一部分来帮助您为基于 IoC 的应用程序编写有效的单元测试。但是,对于某些单元测试场景,Spring 框架提供了模拟对象和测试支持类,本章将对此进行描述。

模拟对象

Spring 包含许多专门用于模拟的包

环境

org.springframework.mock.env包包含EnvironmentPropertySource抽象的模拟实现(参见Bean 定义配置文件PropertySource抽象)。MockEnvironmentMockPropertySource对于开发依赖于环境特定属性的代码的容器外测试很有用。

Servlet API

org.springframework.mock.web包包含一套完整的 Servlet API 模拟对象,这些对象对于测试 Web 上下文、控制器和过滤器很有用。这些模拟对象针对 Spring 的 Web MVC 框架的使用,通常比动态模拟对象(如EasyMock)或替代的 Servlet API 模拟对象(如MockObjects)更方便使用。

从 Spring Framework 6.0 开始,org.springframework.mock.web中的模拟对象基于 Servlet 6.0 API。

MockMvc 基于模拟 Servlet API 对象构建,为 Spring MVC 提供了一个集成测试框架。参见MockMvc

Spring Web Reactive

org.springframework.mock.http.server.reactive包包含ServerHttpRequestServerHttpResponse的模拟实现,用于 WebFlux 应用程序。org.springframework.mock.web.server包包含一个模拟ServerWebExchange,它依赖于这些模拟请求和响应对象。

MockServerHttpRequestMockServerHttpResponse都扩展自与服务器特定实现相同的抽象基类,并与其共享行为。例如,创建后,模拟请求是不可变的,但您可以使用ServerHttpRequestmutate()方法来创建修改后的实例。

为了使模拟响应能够正确地实现写入契约并返回写入完成句柄(即Mono<Void>),它默认使用带有cache().then()Flux,它缓冲数据并使其在测试中可用于断言。应用程序可以设置自定义写入函数(例如,测试无限流)。

WebTestClient基于模拟请求和响应构建,提供对在没有 HTTP 服务器的情况下测试 WebFlux 应用程序的支持。该客户端也可用于对正在运行的服务器进行端到端测试。

单元测试支持类

Spring 包含许多可以帮助进行单元测试的类。它们分为两类

通用测试实用程序

org.springframework.test.util包包含一些用于单元和集成测试的通用实用程序。

AopTestUtils是与 AOP 相关的实用程序方法的集合。您可以使用这些方法获取对隐藏在一个或多个 Spring 代理后面的底层目标对象的引用。例如,如果您使用 EasyMock 或 Mockito 等库将 Bean 配置为动态模拟,并且模拟包装在 Spring 代理中,则可能需要直接访问底层模拟以对其配置期望并执行验证。对于 Spring 的核心 AOP 实用程序,请参见AopUtilsAopProxyUtils

ReflectionTestUtils是基于反射的实用程序方法的集合。您可以在需要更改常量值、设置非public字段、调用非publicsetter 方法或调用非public配置或生命周期回调方法的测试场景中使用这些方法,用于以下用例

  • ORM 框架(如 JPA 和 Hibernate),与 public setter 方法相比,这些框架允许对域实体中的privateprotected字段进行访问。

  • Spring 对注解的支持(如@Autowired@Inject@Resource),这些注解为privateprotected字段、setter 方法和配置方法提供依赖注入。

  • 使用@PostConstruct@PreDestroy等注解进行生命周期回调方法。

TestSocketUtils是一个简单的实用程序,用于查找localhost上可用的 TCP 端口,用于集成测试场景。

TestSocketUtils可用于在可用的随机端口上启动外部服务器的集成测试。但是,这些实用程序不能保证随后某个给定端口的可用性,因此不可靠。建议不要使用TestSocketUtils查找服务器可用的本地端口,而是依靠服务器能够在它选择的或操作系统分配的随机临时端口上启动的能力。要与该服务器交互,您应该查询服务器以获取它当前使用的端口。

Spring MVC 测试实用程序

org.springframework.test.web包包含ModelAndViewAssert,您可以将其与 JUnit、TestNG 或任何其他测试框架结合使用,用于处理 Spring MVC ModelAndView对象的单元测试。

单元测试 Spring MVC 控制器
要将您的 Spring MVC Controller类作为 POJO 进行单元测试,请将ModelAndViewAssert与 Spring 的Servlet API 模拟中的MockHttpServletRequestMockHttpSession等结合使用。要对您的 Spring MVC 和 REST Controller类进行彻底的集成测试,并结合您的 Spring MVC 的WebApplicationContext配置,请改用MockMvc