Spring 5 中文解析核心篇-集成测试之TestContext(上)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring 5 中文解析测试篇-集成测试之TestContext(上)

Spring TestContext 框架(位于org.springframework.test.context包中)提供了通用的、注解驱动的单元和集成测试支持,这些支持与所使用的测试框架无关。TestContext框架还非常重视约定优于配置,你可以通过基于注解的配置覆盖合理的默认值。

除了通用测试基础结构之外,TestContext框架还为JUnit 4,JUnit Jupiter(AKA JUnit 5)和TestNG提供了显式支持。对于JUnit 4和TestNG,Spring提供了抽象支持类。此外,Spring为JUnit 4提供了自定义JUnit Runner和自定义JUnit规则,以及JUnit Jupiter的自定义扩展,可让你编写所谓的POJO测试类。不需要POJO测试类来扩展特定的类层次结构,例如抽象支持类。下一节概述了TestContext框架的内部。如果你仅对使用框架感兴趣,而对使用自己的自定义监听器或自定义加载程序进行扩展不感兴趣,请直接转到配置(上下文管理依赖项注入事务管理支持类注解支持部分。

3.5.1 关键抽象

该框架的核心由TestContextManager类和TestContextTestExecutionListenerSmartContextLoader接口组成。为每个测试类创建一个TestContextManager(例如,用于在JUnit Jupiter中的单个测试类中执行所有测试方法)。反过来,TestContextManager管理包含当前测试上下文的TestContext。随着测试的进行,TestContextManager还更新了TestContext的状态,并委托给TestExecutionListener实现,该实现通过提供依赖项注入,管理事务等来检测实际的测试执行。SmartContextLoader负责为给定的测试类加载ApplicationContext。有关更多信息和各种实现的示例,请参见javadoc和Spring测试套件。

TestContext

TestContext封装了在其中执行测试的上下文(与使用中的实际测试框架无关),并为其负责的测试实例提供了上下文管理和缓存支持。如果需要,TestContext还委托给SmartContextLoader来加载ApplicationContext

TestContextManager

TestContextManager是Spring TestContext 框架的主要入口点,并负责管理单个TestContext并在定义良好的测试执行点向每个注册的TestExecutionListener发出事件信号:

  • 在任何before类之前或在特定测试框架的所有方法之前。
  • 测试实例后处理。
  • 在任何before或在每个特定测试框架的方法之前。
  • 在执行测试方法之前但在测试设置之后。
  • 在测试方法执行之后,但在测试拆卸之前。
  • 之后的任何方法或之后的每一个特定的测试框架。
  • 在特定测试框架的任何类后或所有方法之后。

TestExecutionListener

TestExecutionListener定义用于对由注册监听器的TestContextManager发布的测试执行事件做出反应的API。请参阅TestExecutionListener配置。

上下文加载器

ContextLoader是一个策略接口,用于为Spring TestContext 框架管理的集成测试加载ApplicationContext。你应该实现SmartContextLoader而不是此接口,以提供对组件类,激活的bean定义配置文件、测试属性源、上下文层次结构和WebApplicationContext支持的支持。

SmartContextLoaderContextLoader接口的扩展,它取代了原始的最小ContextLoader SPI。具体来说,SmartContextLoader可以选择处理资源位置、组件类或上下文初始化器。此外,SmartContextLoader可以在其加载的上下文中设置激活Bean定义配置文件并测试属性源。

Spring提供了以下实现:

  • DelegatingSmartContextLoader: 它是两个默认加载器之一,它在内部委派给AnnotationConfigContextLoaderGenericXmlContextLoaderGenericGroovyXmlContextLoader,具体取决于为测试类声明的配置或默认位置或默认配置类的存在。仅当Groovy在类路径上时才启用Groovy支持。
  • WebDelegatingSmartContextLoader: 它是两个默认加载器之一,它在内部委派给AnnotationConfigWebContextLoader、GenericXmlWebContextLoader或GenericGroovyXmlWebContextLoader,具体取决于为测试类声明的配置或默认位置或默认配置类的存在。仅当测试类上存在@WebAppConfiguration时,才使用Web ContextLoader。仅当Groovy在类路径上时才启用Groovy支持。
  • AnnotationConfigContextLoader:从组件类加载标准ApplicationContext
  • AnnotationConfigWebContextLoader: 从组件类加载WebApplicationContext
  • GenericGroovyXmlContextLoader: 从Groovy脚本或XML配置文件的资源位置加载标准ApplicationContext
  • GenericGroovyXmlWebContextLoader: 从Groovy脚本或XML配置文件的资源位置加载WebApplicationContext
  • GenericXmlContextLoader: 从XML资源位置加载标准ApplicationContext
  • GenericXmlWebContextLoader: 从XML资源位置加载WebApplicationContext
  • GenericPropertiesContextLoader:从Java属性文件加载标准ApplicationContext
3.5.2 引导TestContext框架

Spring TestContext 框架内部的默认配置足以满足所有常见用例。但是,有时开发团队或第三方框架希望更改默认的ContextLoader,实现自定义的TestContextContextCache,扩展默认的ContextCustomizerFactoryTestExecutionListener实现等等。为了对TestContext框架的运行方式进行低级别控制,Spring提供了引导策略。

TestContextBootstrapper定义了用于引导TestContext框架的SPI。TestContextManager使用TestContextBootstrapper加载当前测试的TestExecutionListener实现并构建它管理的TestContext。你可以直接使用@BootstrapWith或作为元注解,为测试类(或测试类层次结构)配置自定义引导策略。如果没有通过使用@BootstrapWith显式配置引导程序,则根据@WebAppConfiguration的存在,使用DefaultTestContextBootstrapperWebTestContextBootstrapper

由于TestContextBootstrapper SPI将来可能会更改(以适应新的需求),我们强烈建议实现者不要直接实现此接口,而应扩展AbstractTestContextBootstrapper或其具体子类之一。

3.5.3 TestExecutionListener配置

Spring提供了以下TestExecutionListener实现,这些实现默认情况下按以下顺序注册:

  • ServletTestExecutionListener:为WebApplicationContext配置Servlet API模拟。
  • DirtiesContextBeforeModesTestExecutionListener:处理before模式的@DirtiesContext注解。
  • DependencyInjectionTestExecutionListener: 为测试实例提供依赖项注入。
  • DirtiesContextTestExecutionListener: 处理after模式的@DirtiesContext注解。
  • TransactionalTestExecutionListener: 提供具有默认回滚语义的事务测试执行。
  • SqlScriptsTestExecutionListener: 运行使用@Sql注释配置的SQL脚本。
  • EventPublishingTestExecutionListener: 将测试执行事件发布到测试的ApplicationContext中(请参阅测试执行事件)。

注册TestExecutionListener实现

你可以使用@TestExecutionListeners注解为测试类及其子类注解TestExecutionListener实现。有关详细信息和示例,请参见注解支持@TestExecutionListeners的javadoc。

默认TestExecutionListener实现自动发现

通过使用@TestExecutionListeners注册TestExecutionListener实现适用于有限测试方案中使用的自定义监听器。但是,如果需要在整个测试套件中使用自定义监听器,则会变得很麻烦。通过SpringFactoriesLoader机制支持自动发现默认的TestExecutionListener实现,可以解决这个问题。

具体来说,spring-test模块在其META-INF/spring.factories属性文件中的keyorg.springframework.test.context.TestExecutionListener下声明所有核心默认TestExecutionListener实现。第三方框架和开发人员可以通过自己的META-INF/spring.factories属性文件以相同的方式将自己的TestExecutionListener实现贡献到默认监听器列表中。

TestExecutionListener顺序实现

TestContext框架通过上述SpringFactoriesLoader机制发现默认TestExecutionListener实现时,实例化的监听器将使用Spring的AnnotationAwareOrderComparator进行排序,该类将使用Spring的Ordered接口和@Order注解进行排序。Spring提供的AbstractTestExecutionListener和所有默认的TestExecutionListener实现以适当的值实现Ordered。因此,第三方框架和开发人员应通过实施Ordered或声明@Order来确保按默认顺序注册其默认的TestExecutionListener实现。请参阅javadoc以获取核心默认TestExecutionListener实现的getOrder()方法,以获取有关为每个核心监听器分配哪些值的详细信息。

TestExecutionListener合并实现

如果通过@TestExecutionListeners注册了自定义TestExecutionListener,则不会注册默认监听器。在大多数常见的测试方案中,这有效地迫使开发人员手动声明除任何自定义监听器之外的所有默认监听器。

下面的清单演示了这种配置样式:

@ContextConfiguration
@TestExecutionListeners({
    MyCustomTestExecutionListener.class,
    ServletTestExecutionListener.class,
    DirtiesContextBeforeModesTestExecutionListener.class,
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    SqlScriptsTestExecutionListener.class
})
class MyTest {
    // class body...
}

这种方法的挑战在于,它要求开发人员确切地知道默认情况下注册了哪些监听器。此外,默认的监听器集可以随版本的不同而变化-例如,在Spring框架4.1中引入了SqlScriptsTestExecutionListener,在Spring框架4.2中引入了DirtiesContextBeforeModesTestExecutionListener。此外,诸如Spring Boot和Spring Security之类的第三方框架通过使用上述自动发现机制注册了自己的默认TestExecutionListener实现。

为避免必须了解并重新声明所有默认监听器,可以将@TestExecutionListenersmergeMode属性设置为MergeMode.MERGE_WITH_DEFAULTSMERGE_WITH_DEFAULTS表示应将本地声明的监听器与默认监听器合并。合并算法可确保从列表中删除重复项,并确保根据AnnotationAwareOrderComparator的语义对合并后的监听器集进行排序,如Ordering TestExecutionListener实现中所述。如果监听器实现Ordered或使用@Order进行注解,则它可以影响将其与默认值合并的位置。否则,合并时,本地声明的监听器将追加到默认侦听器列表中。

例如,如果上一个示例中的MyCustomTestExecutionListener类将顺序值(例如500)配置为小于ServletTestExecutionListener的顺序(恰好是1000),则MyCustomTestExecutionListener可以自动与默认列表合并。在ServletTestExecutionListener前面,并且前面的示例可以替换为以下示例:

@ContextConfiguration
@TestExecutionListeners(
    listeners = MyCustomTestExecutionListener.class,
    mergeMode = MERGE_WITH_DEFAULTS
)
class MyTest {
    // class body...
}
3.5.4 测试执行事件

Spring框架5.2中引入的EventPublishingTestExecutionListener提供了一种实现自定义TestExecutionListener的替代方法。测试的ApplicationContext中的组件可以监听EventPublishingTestExecutionListener发布的以下事件,每个事件都与TestExecutionListener API中的方法相对应。

  • BeforeTestClassEvent
  • PrepareTestInstanceEvent
  • BeforeTestMethodEvent
  • BeforeTestExecutionEvent
  • AfterTestExecutionEvent
  • AfterTestMethodEvent
  • AfterTestClassEvent

只有当ApplicationContext已经加载时,才会发布这些事件。

这些事件可能由于各种原因被使用,例如重置模拟bean或跟踪测试执行。使用测试执行事件而不是实现自定义TestExecutionListener的一个优势是,测试执行事件可以由在测试ApplicationContext中注册的任何Spring bean所使用,并且此类bean可以直接受益于依赖项注入和ApplicationContext的其他功能。相反,TestExecutionListenerApplicationContext中不是bean。

为了监听测试执行事件,Spring Bean可以选择实现org.springframework.context.ApplicationListener接口。或者,可以使用@EventListener注解监听器方法,并将监听方法配置为监听上面列出的特定事件类型之一(请参阅基于注解的事件监听器)。由于这种方法的流行,Spring提供了以下专用的@EventListener注解,以简化测试执行事件监听器的注册。这些注解驻留在org.springframework.test.context.event.annotation包中。

  • @BeforeTestClass
  • @PrepareTestInstance
  • @BeforeTestMethod
  • @BeforeTestExecution
  • @AfterTestExecution
  • @AfterTestMethod
  • @AfterTestClass

参考代码:org.liyong.test.annotation.test.spring.TestExecutionEventTest

异常处理

默认情况下,如果测试执行事件监听器在使用事件时抛出异常,则该异常将传播到使用中的基础测试框架(例如JUnit或TestNG)。例如,如果使用BeforeTestMethodEvent导致异常,则相应的测试方法将因异常而失败。相反,如果异步测试执行事件监听器引发异常,则该异常不会传播到基础测试框架。有关异步异常处理的更多详细信息,请查阅@EventListener类级javadoc。

异步监听器

如果你希望特定的测试执行事件监听器异步处理事件,你可以使用Spring的常规@Async支持。有关更多详细信息,请查阅@EventListener的类级javadoc。

参考代码:org.liyong.test.annotation.test.spring.TestExecutionEventTest

作者

个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。关注公众号:青年IT男 获取最新技术文章推送!

博客地址: http://youngitman.tech

CSDN: https://blog.csdn.net/liyong1028826685

微信公众号:

技术交流群:

目录
相关文章
|
11天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
39 2
|
27天前
|
数据采集 安全 数据管理
深度解析:DataHub的数据集成与管理策略
【10月更文挑战第23天】DataHub 是阿里云推出的一款数据集成与管理平台,旨在帮助企业高效地处理和管理多源异构数据。作为一名已经有一定 DataHub 使用经验的技术人员,我深知其在数据集成与管理方面的强大功能。本文将从个人的角度出发,深入探讨 DataHub 的核心技术、工作原理,以及如何实现多源异构数据的高效集成、数据清洗与转换、数据权限管理和安全控制措施。通过具体的案例分析,展示 DataHub 在解决复杂数据管理问题上的优势。
141 1
|
29天前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
25天前
|
安全 测试技术 数据安全/隐私保护
原生鸿蒙应用市场开发者服务的技术解析:从集成到应用发布的完整体验
原生鸿蒙应用市场开发者服务的技术解析:从集成到应用发布的完整体验
|
1月前
|
测试技术 API 开发者
精通.NET单元测试:MSTest、xUnit、NUnit全面解析
【10月更文挑战第15天】本文介绍了.NET生态系统中最流行的三种单元测试框架:MSTest、xUnit和NUnit。通过示例代码展示了每种框架的基本用法和特点,帮助开发者根据项目需求和个人偏好选择合适的测试工具。
39 3
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
113 5
|
1月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
109 1
|
1月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
71 0
|
1月前
|
Java Spring
springboot 学习十一:Spring Boot 优雅的集成 Lombok
这篇文章是关于如何在Spring Boot项目中集成Lombok,以简化JavaBean的编写,避免冗余代码,并提供了相关的配置步骤和常用注解的介绍。
105 0
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
70 0

推荐镜像

更多
下一篇
无影云桌面