单元测试
依赖注入应该使您的代码对容器的依赖程度低于传统 J2EE / Java EE 开发中的依赖程度。构成应用程序的 POJO 应该在 JUnit 或 TestNG 测试中可测试,使用 new
运算符实例化对象,无需 Spring 或任何其他容器。您可以使用 模拟对象(结合其他有价值的测试技术)来隔离测试您的代码。如果您遵循 Spring 的架构建议,则由此产生的代码库的干净分层和组件化将促进更轻松的单元测试。例如,您可以通过存根或模拟 DAO 或存储库接口来测试服务层对象,而无需在运行单元测试时访问持久数据。
真正的单元测试通常运行速度非常快,因为没有运行时基础设施需要设置。将真正的单元测试作为开发方法的一部分可以提高您的生产力。您可能不需要本测试章节的这一部分来帮助您为基于 IoC 的应用程序编写有效的单元测试。但是,对于某些单元测试场景,Spring 框架提供了模拟对象和测试支持类,本章将对此进行介绍。
模拟对象
Spring 包含多个专门用于模拟的包
环境
org.springframework.mock.env
包包含 Environment
和 PropertySource
抽象的模拟实现(参见 Bean 定义配置文件 和 PropertySource
抽象)。MockEnvironment
和 MockPropertySource
有助于为依赖于环境特定属性的代码开发容器外测试。
JNDI
org.springframework.mock.jndi
包包含 JNDI SPI 的部分实现,您可以使用它为测试套件或独立应用程序设置简单的 JNDI 环境。例如,如果 JDBC DataSource
实例在测试代码中绑定到与 Jakarta EE 容器中相同的 JNDI 名称,则可以在测试场景中无需修改即可重用应用程序代码和配置。
从 Spring Framework 5.2 开始,org.springframework.mock.jndi 包中的模拟 JNDI 支持正式弃用,取而代之的是来自第三方(例如 Simple-JNDI)的完整解决方案。
|
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。
|
Spring MVC 测试框架基于模拟 Servlet API 对象,为 Spring MVC 提供了一个集成测试框架。参见 MockMvc。
Spring Web Reactive
org.springframework.mock.http.server.reactive
包含 ServerHttpRequest
和 ServerHttpResponse
的模拟实现,用于 WebFlux 应用程序。org.springframework.mock.web.server
包含一个模拟 ServerWebExchange
,它依赖于这些模拟请求和响应对象。
MockServerHttpRequest
和 MockServerHttpResponse
都扩展自与服务器特定实现相同的抽象基类,并与它们共享行为。例如,模拟请求在创建后是不可变的,但可以使用 ServerHttpRequest
的 mutate()
方法创建修改后的实例。
为了使模拟响应正确地实现写入契约并返回写入完成句柄(即 Mono<Void>
),它默认使用带有 cache().then()
的 Flux
,它缓冲数据并使其在测试中可用于断言。应用程序可以设置自定义写入函数(例如,测试无限流)。
WebTestClient 基于模拟请求和响应,为测试 WebFlux 应用程序提供支持,而无需 HTTP 服务器。该客户端也可以用于与正在运行的服务器进行端到端测试。
单元测试支持类
Spring 包含许多可以帮助进行单元测试的类。它们分为两类
通用测试实用程序
org.springframework.test.util
包含几个用于单元测试和集成测试的通用实用程序。
AopTestUtils
是一个包含 AOP 相关实用程序方法的集合。可以使用这些方法获取隐藏在 Spring 代理后面的底层目标对象的引用。例如,如果使用 EasyMock 或 Mockito 等库将 bean 配置为动态模拟,并且模拟包装在 Spring 代理中,则可能需要直接访问底层模拟以对其配置期望并执行验证。对于 Spring 的核心 AOP 实用程序,请参见 AopUtils
和 AopProxyUtils
。
ReflectionTestUtils
是一个包含基于反射的实用程序方法的集合。可以使用这些方法在需要更改常量值、设置非 public
字段、调用非 public
setter 方法或调用非 public
配置或生命周期回调方法的测试场景中,在测试应用程序代码时用于以下用例
-
ORM 框架(例如 JPA 和 Hibernate)允许对域实体中的属性使用 `private` 或 `protected` 字段访问,而不是使用 `public` setter 方法。
-
Spring 支持注解(例如 `@Autowired`、`@Inject` 和 `@Resource`),这些注解为 `private` 或 `protected` 字段、setter 方法和配置方法提供依赖注入。
-
使用 `@PostConstruct` 和 `@PreDestroy` 等注解来定义生命周期回调方法。
TestSocketUtils
是一个简单的实用程序,用于在 `localhost` 上查找可用的 TCP 端口,以便在集成测试场景中使用。
|
Spring MVC 测试实用程序
org.springframework.test.web
包含 ModelAndViewAssert
,您可以将其与 JUnit、TestNG 或任何其他测试框架结合使用,用于处理 Spring MVC ModelAndView
对象的单元测试。
单元测试 Spring MVC 控制器
要将 Spring MVC Controller 类作为 POJO 进行单元测试,请将 ModelAndViewAssert 与 Spring 的 Servlet API 模拟 中的 MockHttpServletRequest 、MockHttpSession 等结合使用。要对 Spring MVC 和 REST Controller 类进行彻底的集成测试,并结合 Spring MVC 的 WebApplicationContext 配置,请使用 Spring MVC 测试框架。
|