单元测试
依赖注入应该使您的代码对容器的依赖性降低,而不像传统的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框架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框架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
包含了用于WebFlux应用程序的ServerHttpRequest
和ServerHttpResponse
的模拟实现。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的MockHttpServletRequest 、MockHttpSession 等Servlet API模拟。要对Spring MVC和REST Controller 类进行彻底的集成测试,结合使用Spring MVC的WebApplicationContext 配置,建议使用Spring MVC 测试框架。 |