Spring 对集成测试的支持和单元的最佳实践测试

时间:2022-11-17 14:05:33

版本 6.0.0

本章介绍了 Spring 对集成测试的支持和单元的最佳实践 测试。Spring团队提倡测试驱动开发(TDD)。春天团队有 发现正确使用反转控制(IoC)确实使两个单元 和集成测试更容易(因为存在二传手方法和适当的 类上的构造函数使它们更容易在测试中连接在一起,而无需 设置服务定位器注册表和类似结构)。

Spring 对集成测试的支持和单元的最佳实践测试

1. 弹簧测试简介

测试是企业软件开发不可或缺的一部分。本章重点介绍 IoC 原则对单元测试的附加值及其优势 Spring 框架对集成测试的支持。(一 企业中测试的彻底处理超出了本参考的范围 手动。

2. 单元测试

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

真正的单元测试通常运行得非常快,因为没有运行时基础结构 建立。强调真正的单元测试作为开发方法的一部分可以提高 您的生产力。您可能不需要测试章节的这一部分来帮助您编写 针对基于 IoC 的应用程序进行有效的单元测试。对于某些单元测试方案, 但是,Spring 框架提供了模拟对象和测试支持类,它们 在本章中进行了介绍。

2.1. 模拟对象

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

  • 环境
  • 金迪
  • Servlet API
  • 弹簧网反应式

2.1.1. 环境

该包包含 theandabstractions 的模拟实现(请参阅Bean 定义配置文件和PropertySourceAbstraction).并且对于开发很有用 对依赖于特定于环境的属性的代码进行容器外测试。​​org.springframework.mock.env​​​​Environment​​​​PropertySource​​​​MockEnvironment​​​​MockPropertySource​

2.1.2. JNDI

该软件包包含 JNDI 的部分实现 SPI,可用于为测试套件或独立设置简单的 JNDI 环境 应用。例如,如果 JDBC 实例绑定到同一个 JNDI 测试代码中的名称与在 Jakarta EE 容器中的名称一样,您可以重用这两个应用程序代码 和测试方案中的配置,无需修改。​​org.springframework.mock.jndi​​​​DataSource​

软件包中的模拟 JNDI 支持是 从 Spring Framework 5.2 开始正式弃用,转而支持第三个的完整解决方案 诸如​​Simple-JNDI​​​之类的政党。​​org.springframework.mock.jndi​

2.1.3. servlet API

该软件包包含一套全面的 Servlet API 模拟对象,用于测试 Web 上下文、控制器和筛选器。这些 模拟对象针对的是Spring的Web MVC框架的使用,通常更多 比动态模拟对象(如EasyMock)更方便使用 或替代的 Servlet API 模拟对象(如MockObjects)。​​org.springframework.mock.web​

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

Spring MVC 测试框架建立在模拟 Servlet API 对象之上,以提供 Spring MVC 的集成测试框架。参见模拟Mvc。

2.1.4. 弹簧网反应式

该包包含模拟实现 和用于 WebFlux 应用程序。该包包含一个模拟 取决于这些模拟请求和响应对象。​​org.springframework.mock.http.server.reactive​​​​ServerHttpRequest​​​​ServerHttpResponse​​​​org.springframework.mock.web.server​​​​ServerWebExchange​

从同一个抽象扩展两者 基类作为特定于服务器的实现,并与其共享行为。为 例如,模拟请求一旦创建就不可变,但您可以使用方法 发件人以创建修改后的实例。​​MockServerHttpRequest​​​​MockServerHttpResponse​​​​mutate()​​​​ServerHttpRequest​

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

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

2.2. 单元测试支持类

Spring 包含许多可以帮助进行单元测试的类。他们一分为二 类别:

  • 一般测试实用程序
  • 春季 MVC 测试实用程序

2.2.1. 一般测试实用程序

该软件包包含几个通用实用程序 用于单元测试和集成测试。org.springframework.test.util

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

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

  • ORM框架(如JPA和Hibernate)可以容纳 访问域实体中属性的 Setter(与 Setter) 方法相反。privateprotectedpublic
  • Spring 对注释的支持(例如,和), 为字段、二传手方法提供依赖注入, 和配置方法。@Autowired@Inject@Resourceprivateprotected
  • 使用注释,例如 andfor 生命周期回调 方法。@PostConstruct@PreDestroy

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

2.2.2. 弹簧 MVC 测试实用程序

该软件包包含ModelAndViewAssert,您 可以与JUnit,TestNG或任何其他测试框架结合使用以进行单元测试 处理Spring MVC对象。​​org.springframework.test.web​​​​ModelAndView​

3. 集成测试

本节(本章其余大部分内容)介绍 Spring 的集成测试 应用。它包括以下主题:

  • 概述
  • 集成测试的目标
  • JDBC 测试支持
  • 附注
  • Spring TestContext Framework
  • 模拟MVC

3.1. 概述

能够在不需要的情况下执行一些集成测试非常重要 部署到应用程序服务器或连接到其他企业基础结构。 这样做可以测试以下内容:

  • Spring IoC 容器上下文的正确接线。
  • 使用 JDBC 或 ORM 工具访问数据。这可能包括正确性等内容 的 SQL 语句、休眠查询、JPA 实体映射等。

Spring 框架为模块中的集成测试提供了一流的支持。实际 JAR 文件的名称可能包含发行版本 也可能是长篇,具体取决于您获得的位置 它来自(有关说明,请参阅依赖项管理部分)。该库包括包,其中 包含用于使用 Spring 容器进行集成测试的有价值的类。此测试 不依赖于应用程序服务器或其他部署环境。此类测试是 运行速度比单元测试慢,但比等效的硒测试快得多,或者 依赖于部署到应用程序服务器的远程测试。​​spring-test​​​​org.springframework.test​​​​org.springframework.test​

单元和集成测试支持以注释驱动的Spring TestContext Framework的形式提供。TestContext 框架是 与使用的实际测试框架无关,允许测试检测 在各种环境中,包括JUnit,TestNG等。

3.2. 集成测试的目标

Spring 的集成测试支持具有以下主要目标:

  • 在测试之间管理Spring IoC 容器缓存。
  • 提供测试夹具实例的依赖关系注入。
  • 提供适合集成测试的事务管理。
  • 提供特定于Spring 的基类,以帮助 编写集成测试的开发人员。

接下来的几节将介绍每个目标,并提供实现和 配置详细信息。

3.2.1. 上下文管理和缓存

Spring TestContext Framework 提供了 Spring 实例和实例以及缓存的一致加载。 这些背景。支持加载上下文的缓存非常重要,因为 启动时间可能会成为一个问题——不是因为 Spring 本身的开销,而是 因为 Spring 容器实例化的对象需要时间来实例化。为 例如,具有 50 到 100 个休眠映射文件的项目可能需要 10 到 20 秒才能 加载映射文件,并在每次测试中运行每个测试之前产生该成本 夹具会导致整体测试运行速度变慢,从而降低开发人员的工作效率。​​ApplicationContext​​​​WebApplicationContext​

测试类通常声明 XML 或 Groovy 的资源位置数组 配置元数据(通常在类路径中)或组件类数组 用于配置应用程序。这些位置或类与 或 类似于为生产指定的 inor 其他配置文件 部署。​​web.xml​

默认情况下,加载后,配置将重用于每个测试。 因此,每个测试套件仅产生一次设置成本,随后的测试执行 要快得多。在这种情况下,术语“测试套件”是指在同一环境中运行的所有测试 JVM — 例如,所有测试都从给定项目的 Ant、Maven 或 Gradle 构建中运行 或模块。在极少数情况下,测试会损坏应用程序上下文并需要 重新加载(例如,通过修改 Bean 定义或应用程序的状态) 对象)可以将测试上下文框架配置为重新加载配置和 在执行下一个测试之前重新生成应用程序上下文。​​ApplicationContext​

请参阅上下文管理和上下文缓存与 测试上下文框架。

3.2.2. 测试治具的依赖注入

当 TestContext 框架 加载 应用程序 上下文 时, 它 可以 选择 使用依赖关系注入配置测试类的实例。这提供了一个 使用预配置的 bean 设置测试夹具的便捷机制 应用程序上下文。这里的一个重要好处是,您可以重用应用程序上下文 跨各种测试场景(例如,用于配置 Spring 管理的对象) 图、事务代理、实例等),从而避免了 需要为单个测试用例复制复杂的测试夹具设置。​​DataSource​

例如,考虑一个场景,其中我们有一个类 () 实现域实体的数据访问逻辑。我们想写 测试以下方面的集成测试:​​HibernateTitleRepository​​​​Title​

  • 弹簧配置:基本上,与bean配置相关的一切都正确和存在吗?HibernateTitleRepository
  • 休眠映射文件配置:所有映射是否正确,并且是 是否正确设置延迟加载?
  • 的逻辑:是否配置了此类的实例 按预期执行?HibernateTitleRepository

请参阅使用TestContext 框架对测试夹具进行依赖关系注入。

3.2.3. 事务管理

在访问真实数据库的测试中,一个常见问题是它们对 持久性存储。即使使用开发数据库,对状态的更改也可能会 影响将来的测试。此外,许多操作(例如插入或修改持久化) 数据 — 不能在事务之外执行(或验证)。

TestContext 框架解决了这个问题。默认情况下,框架创建 为每个测试回滚事务。您可以编写可以假设存在的代码 的交易。如果在测试中调用事务代理对象,它们的行为 根据其配置的事务语义正确。此外,如果测试 方法在事务中运行时删除所选表的内容 为测试进行管理,默认情况下事务回滚,数据库返回到 执行测试之前的状态。事务性支持由 使用在测试的应用程序上下文中定义的 ABEAN。​​PlatformTransactionManager​

如果您希望提交事务(不寻常,但偶尔在您想要 特定测试来填充或修改数据库),您可以告诉 TestContext 框架,使事务提交,而不是使用 @Commit注释回滚。

请参阅TestContext 框架的事务管理。

3.2.4. 集成测试的支持类

Spring TestContext 框架提供了几个支持类,这些类 简化集成测试的编写。这些基本测试类提供定义明确的 挂钩到测试框架以及方便的实例变量和方法, 这使您可以访问:​​abstract​

  • 该,用于执行显式 Bean 查找或测试状态 上下文作为一个整体。ApplicationContext
  • A、用于执行SQL语句查询数据库。你可以使用这样的 用于在执行数据库相关之前和之后确认数据库状态的查询 应用程序代码,并且 Spring 确保此类查询在同一范围内运行 事务作为应用程序代码。与ORM工具结合使用时,请确保 以避免误报。JdbcTemplate

此外,您可能希望创建自己的自定义应用程序范围的超类 特定于项目的实例变量和方法。

请参阅TestContext 框架的支持类。

3.3. JDBC 测试支持

该包包含,这是一个 用于简化标准数据库的 JDBC 相关实用程序函数的集合 测试方案。具体来说,提供以下静态实用程序 方法。​​org.springframework.test.jdbc​​​​JdbcTestUtils​​​​JdbcTestUtils​

  • ​countRowsInTable(..)​​:计算给定表中的行数。
  • ​countRowsInTableWhere(..)​​:通过使用 规定条款。WHERE
  • ​deleteFromTables(..)​​:删除指定表中的所有行。
  • ​deleteFromTableWhere(..)​​:使用提供的子句从给定表中删除行。WHERE
  • ​dropTables(..)​​:删除指定的表。

3.4. 注释

本节介绍在测试 Spring 应用程序时可以使用的注释。 它包括以下主题:

  • 弹簧测试注释
  • 标准注释支持
  • 春季 JUnit 4 测试注释
  • 春季JUnit木星测试注释
  • 元注释支持测试。

3.4.1. 弹簧测试注释

Spring 框架提供了以下一组特定于 Spring 的注释,您可以 可以在单元测试和集成测试中与 TestContext 框架结合使用。 请参阅相应的 javadoc 以获取更多信息,包括默认属性 值、属性别名和其他详细信息。

Spring 的测试注释包括以下内容:

  • @BootstrapWith
  • @ContextConfiguration
  • @WebAppConfiguration
  • @ContextHierarchy
  • @ActiveProfiles
  • @TestPropertySource
  • @DynamicPropertySource
  • @DirtiesContext
  • @TestExecutionListeners
  • @RecordApplicationEvents
  • @Commit
  • @Rollback
  • @BeforeTransaction
  • @AfterTransaction
  • @Sql
  • @SqlConfig
  • @SqlMergeMode
  • @SqlGroup
​@BootstrapWith​

​@BootstrapWith​​是一个类级注释,可用于配置 Spring TestContext Framework 是引导的。具体来说,您可以使用 指定自定义。有关更多详细信息,请参阅有关引导TestContext框架的部分。​​@BootstrapWith​​​​TestContextBootstrapper​

​@ContextConfiguration​

​@ContextConfiguration​​定义用于确定如何 加载和配置 ANFOR 集成测试。具体而言,声明应用程序上下文资源或 组件用于加载上下文。​​ApplicationContext​​​​@ContextConfiguration​​​​locations​​​​classes​

资源位置通常是 XML 配置文件或 Groovy 脚本,位于 类路径,而组件类通常是类。然而 资源位置还可以引用文件系统中的文件和脚本,以及组件 类可以是类,类等。有关更多详细信息,请参阅组件类。​​@Configuration​​​​@Component​​​​@Service​

下面的示例演示引用 XML 的注释 文件:​​@ContextConfiguration​

@ContextConfiguration("/test-config.xml") 
class XmlApplicationContextTests {
// class body...
}

以下示例显示了引用类的注释:​​@ContextConfiguration​

@ContextConfiguration(classes = TestConfig.class) 
class ConfigClassApplicationContextTests {
// class body...
}

作为替代方法或除了声明资源位置或组件类之外, 您可以使用来声明类。 以下示例显示了这种情况:​​@ContextConfiguration​​​​ApplicationContextInitializer​

@ContextConfiguration(initializers = CustomContextInitializer.class) 
class ContextInitializerTests {
// class body...
}

您可以选择使用将策略声明为 井。但请注意,您通常不需要显式配置加载程序, 由于默认加载程序支持和任一资源 元件。​​@ContextConfiguration​​​​ContextLoader​​​​initializers​​​​locations​​​​classes​

以下示例同时使用位置和加载程序:

@ContextConfiguration(locations = "/test-context.xml", loader = CustomContextLoader.class) 
class CustomLoaderXmlApplicationContextTests {
// class body...
}

有关更多详细信息,请参阅上下文管理、@Nested测试类配置和 javadocs。​​@ContextConfiguration​

​@WebAppConfiguration​

​@WebAppConfiguration​​是一个类级注释,可用于声明集成测试的加载应为 A。 仅仅存在测试类就可以确保为测试加载 ais,使用默认值 for 到 Web 应用程序根目录的路径(即 资源基本路径)。资源基路径在后台用于创建 ,该路径用作测试的。​​ApplicationContext​​​​WebApplicationContext​​​​@WebAppConfiguration​​​​WebApplicationContext​​​​"file:src/main/webapp"​​​​MockServletContext​​​​ServletContext​​​​WebApplicationContext​

以下示例演示如何使用注释:​​@WebAppConfiguration​

@ContextConfiguration
@WebAppConfiguration
class WebAppTests {
// class body...
}

若要覆盖默认值,可以使用 隐式属性。两者和资源前缀是 支持。如果未提供资源前缀,则假定路径为文件系统 资源。下面的示例演示如何指定类路径资源:​​value​​​​classpath:​​​​file:​

@ContextConfiguration
@WebAppConfiguration("classpath:test-web-resources")
class WebAppTests {
// class body...
}

请注意,必须在单个测试类或测试类中结合使用 等级制度。有关更多详细信息,请参阅@WebAppConfigurationjavadoc。​​@WebAppConfiguration​​​​@ContextConfiguration​

​@ContextHierarchy​

​@ContextHierarchy​​是一个类级注释,用于定义集成测试的实例层次结构。应该是 使用一个或多个实例的列表声明,每个实例 定义上下文层次结构中的级别。以下示例演示了在单个测试类中的用法(也可以使用 在测试类层次结构中):​​ApplicationContext​​​​@ContextHierarchy​​​​@ContextConfiguration​​​​@ContextHierarchy​​​​@ContextHierarchy​

@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@ContextConfiguration("/child-config.xml")
})
class ContextHierarchyTests {
// class body...
}
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = AppConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class WebIntegrationTests {
// class body...
}

如果需要合并或覆盖给定上下文级别的配置 层次结构 在测试类层次结构中,必须通过提供 相同的值到属性在每一个对应的 类层次结构中的级别。请参阅上下文层次结构和@ContextHierarchyjavadoc 有关进一步的示例。​​name​​​​@ContextConfiguration​

​@ActiveProfiles​

​@ActiveProfiles​​是一个类级注释,用于声明哪个 Bean 定义配置文件在加载 ANFOR 时应处于活动状态 集成测试。​​ApplicationContext​

以下示例指示配置文件应处于活动状态:​​dev​

@ContextConfiguration
@ActiveProfiles("dev")
class DeveloperTests {
// class body...
}

以下示例指示配置文件和配置文件都应 保持活跃:​​dev​​​​integration​

@ContextConfiguration
@ActiveProfiles({"dev", "integration"})
class DeveloperIntegrationTests {
// class body...
}

请参阅使用环境配置文件进行上下文配置、@Nested测试类配置和@ActiveProfilesjavadoc 以了解 示例和更多详细信息。

​@TestPropertySource​

​@TestPropertySource​​是可用于配置 要添加到集合的属性文件和内联属性的位置在 for 已加载 集成测试。​​PropertySources​​​​Environment​​​​ApplicationContext​

下面的示例演示如何从类路径声明属性文件

@ContextConfiguration
@TestPropertySource("/test.properties")
class MyIntegrationTests {
// class body...
}

下面的示例演示如何声明内联属性:

@ContextConfiguration
@TestPropertySource(properties = { "timezone = GMT", "port: 4242" })
class MyIntegrationTests {
// class body...
}

有关示例和更多详细信息,请参阅使用测试属性源进行上下文配置。

​@DynamicPropertySource​

​@DynamicPropertySource​​是一个方法级注释,可用于注册要添加到集合中的动态属性 已加载以进行集成测试。动态属性很有用 当您事先不知道属性的价值时 - 例如,如果属性 由外部资源管理,例如由Testcontainers项目管理的容器。​​PropertySources​​​​Environment​​​​ApplicationContext​

下面的示例演示如何注册动态属性:

@ContextConfiguration
class MyIntegrationTests {

static MyExternalServer server = // ...

@DynamicPropertySource
static void dynamicProperties(DynamicPropertyRegistry registry) {
registry.add("server.port", server::getPort);
}

// tests ...
}

有关更多详细信息,请参阅使用动态属性源进行上下文配置。

​@DirtiesContext​

​@DirtiesContext​​表示底层弹簧已被 在执行测试期间脏污(即测试修改或损坏了它 某种方式 — 例如,通过更改单例 Bean 的状态)并且应该是 闭。当应用程序上下文被标记为脏时,将从测试中删除它 框架的缓存并关闭。因此,底层的 Spring 容器是 为需要具有相同配置的上下文的任何后续测试重新生成 元数据。​​ApplicationContext​

您可以在 相同的类或类层次结构。在这种情况下,标记为 在任何此类注释方法之前或之后以及当前之前或之后都脏 测试类,具体取决于配置和。​​@DirtiesContext​​​​ApplicationContext​​​​methodMode​​​​classMode​

以下示例说明了上下文何时会因各种 配置方案:

  • 在当前测试类之前,在类模式设置为 的类上声明时。​​BEFORE_CLASS​
@DirtiesContext(classMode = BEFORE_CLASS) 
class FreshContextTests {
// some tests that require a new Spring container
}
  • 在当前测试类之后,当在类模式设置为(即默认类模式)的类上声明时。​​AFTER_CLASS​
@DirtiesContext 
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
  • 在当前测试类中的每个测试方法之前,在具有类的类上声明时 模式设置为​​BEFORE_EACH_TEST_METHOD.​
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD) 
class FreshContextTests {
// some tests that require a new Spring container
}
  • 在当前测试类中的每个测试方法之后,当在具有类的类上声明时 模式设置为​​AFTER_EACH_TEST_METHOD.​
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) 
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
  • 在当前测试之前,在方法模式设置为 的方法上声明时。​​BEFORE_METHOD​
@DirtiesContext(methodMode = BEFORE_METHOD) 
@Test
void testProcessWhichRequiresFreshAppCtx() {
// some logic that requires a new Spring container
}
  • 在当前测试之后,当在方法上声明方法模式设置为(即默认方法模式)时。​​AFTER_METHOD​
@DirtiesContext 
@Test
void testProcessWhichDirtiesAppCtx() {
// some logic that results in the Spring container being dirtied
}

如果在上下文配置为上下文一部分的测试中使用 层次结构,您可以使用标志来控制如何 上下文缓存将被清除。默认情况下,使用穷举算法来清除 上下文缓存,不仅包括当前级别,还包括所有其他上下文 共享当前测试通用的祖先上下文的层次结构。驻留在共同祖先的子层次结构中的所有实例 上下文将从上下文缓存中删除并关闭。如果穷举算法是 对于特定用例的矫枉过正,您可以指定更简单的当前电平算法, 如以下示例所示。​​@DirtiesContext​​​​@ContextHierarchy​​​​hierarchyMode​​​​ApplicationContext​

@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@ContextConfiguration("/child-config.xml")
})
class BaseTests {
// class body...
}

class ExtendedTests extends BaseTests {

@Test
@DirtiesContext(hierarchyMode = CURRENT_LEVEL)
void test() {
// some logic that results in the child context being dirtied
}
}

有关 theandalgorithms 的更多详细信息,请参阅DirtiesContext.HierarchyModejavadoc。​​EXHAUSTIVE​​​​CURRENT_LEVEL​

​@TestExecutionListeners​

​@TestExecutionListeners​​用于注册特定测试类的侦听器,其 子类及其嵌套类。如果您希望全局注册侦听器,则 应通过测试执行侦听器配置中所述的自动发现机制注册它。

下面的示例演示如何注册两个实现:​​TestExecutionListener​

@ContextConfiguration
@TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class})
class CustomTestExecutionListenerTests {
// class body...
}

默认情况下,支持从 超类或封闭类。有关示例和更多详细信息,请参阅@Nested测试类配置和 javadoc @TestExecutionListeners。如果您发现需要切换 返回到使用默认实现,请参阅注释 在注册TestExecutionListener实现中。​​@TestExecutionListeners​​​​TestExecutionListener​

​@RecordApplicationEvents​

​@RecordApplicationEvents​​是一个类级注释,用于指示Spring TestContext 框架记录在执行单个测试期间发布的所有应用程序事件。​​ApplicationContext​

记录的事件可以通过测试中的API访问。​​ApplicationEvents​

有关示例和更多详细信息,请参阅应用程序事件和 @RecordApplicationEventsjavadoc。

​@Commit​

​@Commit​​指示事务测试方法的事务应为 在测试方法完成后提交。您可以用作直接 替换 for以更明确地传达代码的意图。 类似,也可以声明为类级或方法级 注解。​​@Commit​​​​@Rollback(false)​​​​@Rollback​​​​@Commit​

以下示例演示如何使用注释:​​@Commit​

@Commit 
@Test
void testProcessWithoutRollback() {
// ...
}
​@Rollback​

​@Rollback​​指示事务测试方法的事务是否应为 测试方法完成后回滚。如果,事务已滚动 返回。否则,将提交事务(另请参阅@Commit)。春季集成测试的回滚 TestContext Framework 默认为未显式声明的 ifis。​​true​​​​true​​​​@Rollback​

当声明为类级注释时,定义默认回滚 测试类层次结构中所有测试方法的语义。当声明为 方法级标注,定义特定测试的回滚语义 方法,可能覆盖类级语言。​​@Rollback​​​​@Rollback​​​​@Rollback​​​​@Commit​

以下示例导致测试方法的结果不回滚(即 结果提交到数据库):

@Rollback(false) 
@Test
void testProcessWithoutRollback() {
// ...
}
​@BeforeTransaction​

​@BeforeTransaction​​指示注释方法应在 事务已启动,对于已配置为在 使用 Spring'sannotation.methods 的事务 不需要并且可以在基于 Java 8 的接口缺省值上声明 方法。​​void​​​​@Transactional​​​​@BeforeTransaction​​​​public​

以下示例演示如何使用注释:​​@BeforeTransaction​

@BeforeTransaction 
void beforeTransaction() {
// logic to be run before a transaction is started
}
​@AfterTransaction​

​@AfterTransaction​​指示注释方法应在 事务已结束,对于已配置为在 使用 Spring'sannotation.methods 的事务 不需要并且可以在基于 Java 8 的接口缺省值上声明 方法。​​void​​​​@Transactional​​​​@AfterTransaction​​​​public​

@AfterTransaction 
void afterTransaction() {
// logic to be run after a transaction has ended
}
​@Sql​

​@Sql​​用于批注测试类或测试方法,以配置要运行的 SQL 脚本 在集成测试期间针对给定数据库。以下示例演示如何使用 它:

@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"})
void userTest() {
// run code that relies on the test schema and test data
}

有关更多详细信息,请参阅使用 @Sql 以声明方式执行 SQL 脚本。

​@SqlConfig​

​@SqlConfig​​定义用于确定如何分析和运行 SQL 脚本的元数据 配置了注释。以下示例演示如何使用它:​​@Sql​

@Test
@Sql(
scripts = "/test-user-data.sql",
config = @SqlConfig(commentPrefix = "`", separator = "@@")
)
void userTest() {
// run code that relies on the test data
}
​@SqlMergeMode​

​@SqlMergeMode​​用于批注测试类或测试方法,以配置是否 方法级声明与类级声明合并。未在测试类或测试方法上声明 ifis,合并模式 将默认使用。使用 mode,方法级声明将 有效地重写类级声明。​​@Sql​​​​@Sql​​​​@SqlMergeMode​​​​OVERRIDE​​​​OVERRIDE​​​​@Sql​​​​@Sql​

请注意,方法级声明覆盖类级声明。​​@SqlMergeMode​

下面的示例演示如何在类级别使用。​​@SqlMergeMode​

@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
@SqlMergeMode(MERGE)
class UserTests {

@Test
@Sql("/user-test-data-001.sql")
void standardUserProfile() {
// run code that relies on test data set 001
}
}

下面的示例演示如何在方法级别使用。​​@SqlMergeMode​

@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
class UserTests {

@Test
@Sql("/user-test-data-001.sql")
@SqlMergeMode(MERGE)
void standardUserProfile() {
// run code that relies on test data set 001
}
}
​@SqlGroup​

​@SqlGroup​​是聚合多个注释的容器注释。您可以 本机用于声明多个嵌套注释,也可以使用它 结合Java 8对可重复注释的支持,其中可以 在同一类或方法上声明多次,隐式生成此容器 注解。以下示例演示如何声明 SQL 组:​​@Sql​​​​@SqlGroup​​​​@Sql​​​​@Sql​

@Test
@SqlGroup({
@Sql(scripts = "/test-schema.sql", config = @SqlConfig(commentPrefix = "`")),
@Sql("/test-user-data.sql")
)}
void userTest() {
// run code that uses the test schema and test data
}

3.4.2. 标准注释支持

以下注释支持所有配置的标准语义 Spring TestContext Framework。请注意,这些注释并非特定于测试 并且可以在 Spring 框架中的任何位置使用。

  • ​@Autowired​
  • ​@Qualifier​
  • ​@Value​
  • ​@Resource​​(jakarta.annotation) 如果 JSR-250 存在
  • ​@ManagedBean​​(jakarta.annotation) 如果 JSR-250 存在
  • ​@Inject​​(jakarta.inject) 如果 JSR-330 存在
  • ​@Named​​(jakarta.inject) 如果 JSR-330 存在
  • ​@PersistenceContext​​(jakarta.persistence) 如果 JPA 存在
  • ​@PersistenceUnit​​(jakarta.persistence) 如果 JPA 存在
  • ​@Transactional​​(org.springframework.transaction.annotation)具有有限的属性支持

3.4.3. 春季 JUnit 4 测试注释

以下注释仅在与SpringRunner、Spring 的 JUnit 4 结合使用时受支持。 规则,或Spring 的 JUnit 4 支持类:

  • @IfProfileValue
  • @ProfileValueSourceConfiguration
  • @Timed
  • @Repeat
​@IfProfileValue​

​@IfProfileValue​​指示为特定测试启用了带注释的测试 环境。如果配置返回匹配 前提是,测试已启用。否则,测试将被禁用,并且实际上, 忽视。​​ProfileValueSource​​​​value​​​​name​

您可以在类级别、方法级别或两者级别申请。 对于任何 该类或其子类中的方法。具体而言,如果测试是 在类级别和方法级别启用。缺少 意味着隐式启用测试。这类似于 JUnit 4'sannotation 的语义,只是 Always 的存在会禁用测试。​​@IfProfileValue​​​​@IfProfileValue​​​​@IfProfileValue​​​​@Ignore​​​​@Ignore​

以下示例显示具有注释的测试:​​@IfProfileValue​

@IfProfileValue(name="java.vendor", value="Oracle Corporation") 
@Test
public void testProcessWhichRunsOnlyOnOracleJvm() {
// some logic that should run only on Java VMs from Oracle Corporation
}

仅当 Java 供应商是“Oracle 公司”时,才运行此测试。

或者,您可以使用(带有语义)的列表进行配置,以实现对JUnit 4环境中测试组的类似TestNG的支持。 请考虑以下示例:​​@IfProfileValue​​​​values​​​​OR​

@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"}) 
@Test
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
// some logic that should run only for unit and integration test groups
}

针对单元测试和集成测试运行此测试。

​@ProfileValueSourceConfiguration​

​@ProfileValueSourceConfiguration​​是指定类型的类级注释 of在检索通过注释配置的配置文件值时使用。未声明 测试,默认使用。下面的示例演示如何 用:​​ProfileValueSource​​​​@IfProfileValue​​​​@ProfileValueSourceConfiguration​​​​SystemProfileValueSource​​​​@ProfileValueSourceConfiguration​

@ProfileValueSourceConfiguration(CustomProfileValueSource.class) 
public class CustomProfileValueSourceTests {
// class body...
}

使用自定义配置文件值源。

​@Timed​

​@Timed​​指示带批注的测试方法必须在指定的 时间段(以毫秒为单位)。如果文本执行时间超过指定时间 期间,测试失败。

时间段包括运行测试方法本身、测试的任何重复(参见)以及测试夹具的任何设置或拆卸。以下 示例显示了如何使用它:​​@Repeat​

@Timed(millis = 1000) 
public void testProcessWithOneSecondTimeout() {
// some logic that should not take longer than 1 second to run
}

将测试的时间段设置为一秒。

Spring'sannotation 与 JUnit 4 的支持具有不同的语义。具体来说,由于 JUnit 4 处理测试执行超时的方式 (即,通过在单独的测试方法中执行),如果测试时间过长,则抢先使测试失败。春天,在另一边 手,不会先发制人地使测试失败,而是等待测试完成 在失败之前。​​@Timed​​​​@Test(timeout=…)​​​​Thread​​​​@Test(timeout=…)​​​​@Timed​

​@Repeat​

​@Repeat​​指示必须重复运行带批注的测试方法。的数量 在注释中指定要运行测试方法的时间。

要重复的执行范围包括测试方法本身的执行 以及测试夹具的任何设置或拆卸。当与SpringMethodRule 一起使用时,范围还包括 通过实现准备测试实例。这 以下示例显示了如何使用注释:​​TestExecutionListener​​​​@Repeat​

@Repeat(10) 
@Test
public void testProcessRepeatedly() {
// ...
}

重复此测试十次。

3.4.4. 春季 JUnit 木星测试注释

当与SpringExtension 和 JUnitJupiter 结合使用时,支持以下注释。 (即 JUnit 5 中的编程模型):

  • @SpringJUnitConfig
  • @SpringJUnitWebConfig
  • @TestConstructor
  • @NestedTestConfiguration
  • @EnabledIf
  • @DisabledIf
​@SpringJUnitConfig​

​@SpringJUnitConfig​​是一个组合的注释,它结合了 JUnit 木星与 Spring TestContext Framework。它可以在类级别用作插入式 替换。关于配置选项,唯一的 该组件之间的区别 类可以用属性 in 声明。​​@ExtendWith(SpringExtension.class)​​​​@ContextConfiguration​​​​@ContextConfiguration​​​​@ContextConfiguration​​​​@SpringJUnitConfig​​​​value​​​​@SpringJUnitConfig​

下面的示例演示如何使用注释来指定 配置类:​​@SpringJUnitConfig​

@SpringJUnitConfig(TestConfig.class) 
class ConfigurationClassJUnitJupiterSpringTests {
// class body...
}

指定配置类。

下面的示例演示如何使用注释来指定 配置文件的位置:​​@SpringJUnitConfig​

@SpringJUnitConfig(locations = "/test-config.xml") 
class XmlJUnitJupiterSpringTests {
// class body...
}

指定配置文件的位置。

有关更多详细信息,请参阅上下文管理以及 javadoc@SpringJUnitConfig 和更多详细信息。​​@ContextConfiguration​

​@SpringJUnitWebConfig​

​@SpringJUnitWebConfig​​是一个组合的注释,结合了 JUnit Jupiter 和 Spring TestContext 框架。您可以在课堂上使用它 级别作为直接替代品。 关于配置选项,唯一的区别是您可以使用属性 in 声明组件类。此外,您还可以通过使用属性 in 来覆盖属性 fromonly。​​@ExtendWith(SpringExtension.class)​​​​@ContextConfiguration​​​​@WebAppConfiguration​​​​@ContextConfiguration​​​​@WebAppConfiguration​​​​@ContextConfiguration​​​​@SpringJUnitWebConfig​​​​value​​​​@SpringJUnitWebConfig​​​​value​​​​@WebAppConfiguration​​​​resourcePath​​​​@SpringJUnitWebConfig​

下面的示例演示如何使用注释来指定 配置类:​​@SpringJUnitWebConfig​

@SpringJUnitWebConfig(TestConfig.class) 
class ConfigurationClassJUnitJupiterSpringWebTests {
// class body...
}

指定配置类。

下面的示例演示如何使用注释来指定 配置文件的位置:​​@SpringJUnitWebConfig​

@SpringJUnitWebConfig(locations = "/test-config.xml") 
class XmlJUnitJupiterSpringWebTests {
// class body...
}

指定配置文件的位置。

有关更多详细信息,请参阅上下文管理以及 javadoc 的 @SpringJUnitWebConfig,@ContextConfiguration 和 @WebAppConfiguration。

​@TestConstructor​

​@TestConstructor​​是一个类型级注释,用于配置参数 的测试类构造函数是从测试中的组件自动连线的。​​ApplicationContext​

Ifis 在测试类(默认测试)上不存在或元存在 将使用构造函数自动连线模式。有关如何更改的详细信息,请参阅以下提示 默认模式。但是,请注意,本地声明 构造函数优先于两者和默认模式。​​@TestConstructor​​​​@Autowired​​​​@TestConstructor​

​@NestedTestConfiguration​

​@NestedTestConfiguration​​是类型级注释,用于配置 弹簧测试配置注释在封闭的类层次结构中处理 对于内部测试类。

Ifis 在测试类中不存在或元存在,在其 超类型层次结构,或在其封闭类层次结构中,默认封闭类层次结构 将使用配置继承模式。有关如何的详细信息,请参阅下面的提示 更改默认模式。​​@NestedTestConfiguration​

Spring TestContext 框架​尊重语义 以下注释。@NestedTestConfiguration

  • @BootstrapWith
  • @ContextConfiguration
  • @WebAppConfiguration
  • @ContextHierarchy
  • @ActiveProfiles
  • @TestPropertySource
  • @DynamicPropertySource
  • @DirtiesContext
  • @TestExecutionListeners
  • @RecordApplicationEvents
  • @Transactional
  • @Commit
  • @Rollback
  • @Sql
  • @SqlConfig
  • @SqlMergeMode
  • @TestConstructor

有关示例和进一步内容,请参阅@Nested测试类配置 详。

​@EnabledIf​

​@EnabledIf​​用于指示带注释的 JUnit 木星测试类或测试方法 已启用,如果提供的评估结果为 ,则应运行。 具体而言,如果表达式的计算结果等于(忽略大小写),则启用测试。在类级别应用时,所有测试方法 默认情况下,该类中也会自动启用。​​expression​​​​true​​​​Boolean.TRUE​​​​String​​​​true​

表达式可以是以下任何一种:

  • 弹簧表达式语言(SpEL)表达式。例如:@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")
  • 春季环境中可用属性的占位符。 例如:@EnabledIf("${smoke.tests.enabled}")
  • 文本文字。例如:@EnabledIf("true")

但请注意,文本文本不是动态解析的结果 属性占位符的实用价值为零,因为 等价于逻辑上毫无意义。​​@EnabledIf("false")​​​​@Disabled​​​​@EnabledIf("true")​

您可以用作元注释来创建自定义组合注释。为 例如,您可以创建自定义注释,如下所示:​​@EnabledIf​​​​@EnabledOnMac​

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@EnabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Enabled on Mac OS"
)
public @interface EnabledOnMac {}
​@DisabledIf​

​@DisabledIf​​用于指示带注释的JUnit Jupiter测试类或测试 方法已禁用,如果提供的计算结果为 ,则不应运行该方法。具体来说,如果表达式的计算结果等于 到(忽略大小写),测试被禁用。在类级别应用时,所有 该类中的测试方法也会自动禁用。​​expression​​​​true​​​​Boolean.TRUE​​​​String​​​​true​

表达式可以是以下任何一种:

  • 弹簧表达式语言(SpEL)表达式。例如:@DisabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")
  • 春季环境中可用属性的占位符。 例如:@DisabledIf("${smoke.tests.disabled}")
  • 文本文字。例如:@DisabledIf("true")

但请注意,文本文本不是动态解析的结果 属性占位符的实用价值为零,因为 等价于逻辑上毫无意义。​​@DisabledIf("true")​​​​@Disabled​​​​@DisabledIf("false")​

您可以用作元注释来创建自定义组合注释。为 例如,您可以创建自定义注释,如下所示:​​@DisabledIf​​​​@DisabledOnMac​

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@DisabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Disabled on Mac OS"
)
public @interface DisabledOnMac {}

3.4.5. 测试的元注释支持

您可以使用大多数与测试相关的注释作为元注释来创建自定义组合 注释并减少测试套件中的配置重复。

您可以将以下每个内容用作与TestContext 框架结合使用的元注释。

  • ​@BootstrapWith​
  • ​@ContextConfiguration​
  • ​@ContextHierarchy​
  • ​@ActiveProfiles​
  • ​@TestPropertySource​
  • ​@DirtiesContext​
  • ​@WebAppConfiguration​
  • ​@TestExecutionListeners​
  • ​@Transactional​
  • ​@BeforeTransaction​
  • ​@AfterTransaction​
  • ​@Commit​
  • ​@Rollback​
  • ​@Sql​
  • ​@SqlConfig​
  • ​@SqlMergeMode​
  • ​@SqlGroup​
  • ​@Repeat​​ (仅在 JUnit 4 上受支持)
  • ​@Timed​​ (仅在 JUnit 4 上受支持)
  • ​@IfProfileValue​​ (仅在 JUnit 4 上受支持)
  • ​@ProfileValueSourceConfiguration​​ (仅在 JUnit 4 上受支持)
  • ​@SpringJUnitConfig​​ (仅在JUnit Jupiter上支持)
  • ​@SpringJUnitWebConfig​​ (仅在JUnit Jupiter上支持)
  • ​@TestConstructor​​ (仅在JUnit Jupiter上支持)
  • ​@NestedTestConfiguration​​ (仅在JUnit Jupiter上支持)
  • ​@EnabledIf​​ (仅在JUnit Jupiter上支持)
  • ​@DisabledIf​​ (仅在JUnit Jupiter上支持)

请考虑以下示例:

@RunWith(SpringRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class OrderRepositoryTests { }

@RunWith(SpringRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class UserRepositoryTests { }

如果我们发现我们在基于 JUnit 4 的配置中重复上述配置 测试套件,我们可以通过引入自定义组合注释来减少重复 它集中了 Spring 的通用测试配置,如下所示:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTestConfig { }

然后我们可以使用我们的自定义注释来简化 配置各个基于 JUnit 4 的测试类,如下所示:​​@TransactionalDevTestConfig​

@RunWith(SpringRunner.class)
@TransactionalDevTestConfig
public class OrderRepositoryTests { }

@RunWith(SpringRunner.class)
@TransactionalDevTestConfig
public class UserRepositoryTests { }

如果我们编写使用 JUnit Jupiter 的测试,我们可以进一步减少代码重复, 因为 JUnit 5 中的注释也可以用作元注释。请考虑以下事项 例:

@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
class OrderRepositoryTests { }

@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
class UserRepositoryTests { }

如果我们发现我们在 JUnit 中重复上述配置 基于 Jupiter 的测试套件,我们可以通过引入自定义组合来减少重复 集中了 Spring 和 JUnit Jupiter 的通用测试配置的注释, 如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTestConfig { }

然后我们可以使用我们的自定义注释来简化 基于 JUnit Jupiter 的各个测试类的配置,如下所示:​​@TransactionalDevTestConfig​

@TransactionalDevTestConfig
class OrderRepositoryTests { }

@TransactionalDevTestConfig
class UserRepositoryTests { }

由于JUnit Jupiter支持使用,,, 和其他作为元注释,您还可以在 测试方法级别。例如,如果我们希望创建一个组合的注释 来自JUnit Jupiter的theandannotations with theannotation from Spring,我们可以创建anannotation,如 遵循:​​@Test​​​​@RepeatedTest​​​​ParameterizedTest​​​​@Test​​​​@Tag​​​​@Transactional​​​​@TransactionalIntegrationTest​

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@Tag("integration-test") // org.junit.jupiter.api.Tag
@Test // org.junit.jupiter.api.Test
public @interface TransactionalIntegrationTest { }

然后我们可以使用我们的自定义注释来简化 基于JUnit Jupiter的测试方法的配置如下:​​@TransactionalIntegrationTest​

@TransactionalIntegrationTest
void saveOrder() { }

@TransactionalIntegrationTest
void deleteOrder() { }

有关更多详细信息,请参阅Spring 注释编程模型wiki 页面。

3.5. 弹簧测试上下文框架

Spring TestContext Framework(位于软件包中)提供了通用的、注释驱动的单元和集成测试支持,即 与正在使用的测试框架无关。TestContext 框架还放置了一个很棒的 处理约定的重要性而不是配置,具有合理的默认值,您 可以通过基于注释的配置进行覆盖。​​org.springframework.test.context​

除了通用测试基础设施之外,TestContext 框架还提供 显式支持 JUnit 4、JUnit Jupiter(AKA JUnit 5)和 TestNG。对于 JUnit 4 和 TestNG,Spring提供支持类。此外,春天提供了一个定制 JUnitand custom JUnitfor JUnit 4 and a customfor JUnit 木星,让你写所谓的POJO测试类。POJO测试类不是 需要扩展特定的类层次结构,例如支持类。​​abstract​​​​Runner​​​​Rules​​​​Extension​​​​abstract​

以下部分概述了 TestContext 框架的内部结构。 如果您只对使用框架感兴趣,而对扩展它不感兴趣 使用您自己的自定义侦听器或自定义加载程序,请随时直接转到 配置(上下文管理、依赖注入、事务 管理)、支持类和注释支持部分。

3.5.1. 关键抽象

框架的核心由类和,和接口组成。为每个测试类创建的 Ais(例如,用于执行 JUnit Jupiter 中单个测试类中的所有测试方法)。这 反过来,管理 A 保存当前测试的上下文。还随着测试的进行而更新状态 并委托给实现,这些实现检测实际 通过提供依赖项注入、管理事务等来测试执行。负责加载给定测试的 AIS .class。请参阅javadoc和 弹簧测试套件,以获取更多信息和各种实现的示例。​​TestContextManager​​​​TestContext​​​​TestExecutionListener​​​​SmartContextLoader​​​​TestContextManager​​​​TestContextManager​​​​TestContext​​​​TestContextManager​​​​TestContext​​​​TestExecutionListener​​​​SmartContextLoader​​​​ApplicationContext​

​TestContext​

​TestContext​​封装运行测试的上下文(与 使用中的实际测试框架),并提供上下文管理和缓存支持 它负责的测试实例。该 还委托给 ato 加载 anif 请求。​​TestContext​​​​SmartContextLoader​​​​ApplicationContext​

​TestContextManager​

​TestContextManager​​是 Spring TestContext 框架的主要入口点,并且是 负责管理单个和信号事件到每个注册在明确定义的测试执行点:​​TestContext​​​​TestExecutionListener​

  • 在特定测试框架的任何“课前”或“所有”方法之前。
  • 测试实例后处理。
  • 在特定测试框架的任何“之前”或“之前”方法之前。
  • 在执行测试方法之前,但在测试设置之后。
  • 在执行测试方法后,但在测试拆卸之前立即进行。
  • 在特定测试框架的任何“之后”或“之后”方法之后。
  • 在特定测试框架的任何“课后”或“毕竟”方法之后。
​TestExecutionListener​

​TestExecutionListener​​定义用于响应 发布的测试执行事件的 API 侦听器注册的位置。请参阅TestExecutionListener配置。​​TestContextManager​

上下文加载器

​ContextLoader​​是一个策略接口,用于加载 由Spring TestContext Framework管理的集成测试。您应该实现而不是此接口来提供对组件类的支持, 活动 Bean 定义概要文件、测试属性源、上下文层次结构和支持。​​ApplicationContext​​​​SmartContextLoader​​​​WebApplicationContext​

​SmartContextLoader​​是取代 原始的最小 SPI。具体来说,acan 选择 处理资源位置、组件类或上下文初始值设定项。此外,acan 在 它加载的上下文。​​ContextLoader​​​​ContextLoader​​​​SmartContextLoader​​​​SmartContextLoader​

Spring 提供了以下实现:

  • ​DelegatingSmartContextLoader​​:两个默认加载器之一,它在内部委托给 an、a 或 a,具体取决于为 测试类或是否存在默认位置或默认配置类。 仅当 Groovy 位于类路径上时,才会启用 Groovy 支持。AnnotationConfigContextLoaderGenericXmlContextLoaderGenericGroovyXmlContextLoader
  • ​WebDelegatingSmartContextLoader​​:两个默认加载器之一,它在内部委派 到 an、a 或 a,具体取决于声明的配置 测试类或是否存在默认位置或默认配置 类。仅 if 存在于 测试类。仅当 Groovy 位于类路径上时,才会启用 Groovy 支持。AnnotationConfigWebContextLoaderGenericXmlWebContextLoaderGenericGroovyXmlWebContextLoaderContextLoader@WebAppConfiguration
  • ​AnnotationConfigContextLoader​​:从组件加载标准 类。ApplicationContext
  • ​AnnotationConfigWebContextLoader​​:从组件加载 类。WebApplicationContext
  • ​GenericGroovyXmlContextLoader​​:加载标准源资源 作为 Groovy 脚本或 XML 配置文件的位置。ApplicationContext
  • ​GenericGroovyXmlWebContextLoader​​:从资源加载 作为 Groovy 脚本或 XML 配置文件的位置。WebApplicationContext
  • ​GenericXmlContextLoader​​:从 XML 资源加载标准 地点。ApplicationContext
  • ​GenericXmlWebContextLoader​​:从 XML 资源加载 地点。WebApplicationContext

3.5.2. 引导测试上下文框架

Spring TestContext Framework 内部的默认配置是 足以满足所有常见用例。但是,有时开发团队或 第三方框架想要更改默认值,实现 customor,扩充默认的 OF 和实现集,等等。为 对TestContext框架如何运行的这种低级控制,Spring提供了一个 引导策略。​​ContextLoader​​​​TestContext​​​​ContextCache​​​​ContextCustomizerFactory​​​​TestExecutionListener​

​TestContextBootstrapper​​定义用于引导测试上下文框架的 SPI。AI 由 the(英语)用于加载当前测试的实现并构建它所管理的。您可以为 测试类(或测试类层次结构)直接使用或作为 元注释。如果未使用 显式配置引导程序,则使用引导程序或 the,具体取决于是否存在。​​TestContextBootstrapper​​​​TestContextManager​​​​TestExecutionListener​​​​TestContext​​​​@BootstrapWith​​​​@BootstrapWith​​​​DefaultTestContextBootstrapper​​​​WebTestContextBootstrapper​​​​@WebAppConfiguration​

由于SPI将来可能会发生变化(以适应 新要求),我们强烈建议实现者不要实现此接口 直接但更像是延伸其混凝土之一 子类代替。​​TestContextBootstrapper​​​​AbstractTestContextBootstrapper​

3.5.3.配置​​TestExecutionListener​

Spring 提供了以下已注册的实现 默认情况下,完全按以下顺序排列:​​TestExecutionListener​

  • ​ServletTestExecutionListener​​:为 a 配置 Servlet API 模拟。WebApplicationContext
  • ​DirtiesContextBeforeModesTestExecutionListener​​:处理“之前”模式的注释。@DirtiesContext
  • ​ApplicationEventsTestExecutionListener​​:提供对应用程序事件的支持。
  • ​DependencyInjectionTestExecutionListener​​:为测试提供依赖注入 实例。
  • ​DirtiesContextTestExecutionListener​​:处理 的注释 “之后”模式。@DirtiesContext
  • ​TransactionalTestExecutionListener​​:提供事务测试执行 默认回滚语义。
  • ​SqlScriptsTestExecutionListener​​:运行使用注释配置的 SQL 脚本。@Sql
  • ​EventPublishingTestExecutionListener​​:将测试执行事件发布到测试(请参阅测试执行事件)。ApplicationContext
注册实现​​TestExecutionListener​

您可以为测试类显式注册实现,其 子类及其嵌套类(通过使用注释)。有关详细信息和示例,请参阅注释支持和 javadoc@TestExecutionListeners。​​TestExecutionListener​​​​@TestExecutionListeners​

自动发现默认实现​​TestExecutionListener​

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

具体来说,该模块在 其属性文件。第三方框架和开发人员 可以将自己的实现贡献给默认列表 侦听器通过自己的属性以相同的方式 文件。​​spring-test​​​​TestExecutionListener​​​​org.springframework.test.context.TestExecutionListener​​​​META-INF/spring.factories​​​​TestExecutionListener​​​​META-INF/spring.factories​

排序实现​​TestExecutionListener​

当 TestContext 框架发现默认实现时 通过上述机制,实例化的侦听器使用 Spring's,它遵循 Spring 的接口和排序注释,以及 Spring 实现提供的所有默认实现 适当的值。因此,第三方框架和开发人员应确保 它们的默认实现以正确的顺序注册 通过实现或声明。有关核心默认实现的方法,请参阅 javadoc 以获取有关详细信息的内容 值分配给每个核心侦听器。​​TestExecutionListener​​​​SpringFactoriesLoader​​​​AnnotationAwareOrderComparator​​​​Ordered​​​​@Order​​​​AbstractTestExecutionListener​​​​TestExecutionListener​​​​Ordered​​​​TestExecutionListener​​​​Ordered​​​​@Order​​​​getOrder()​​​​TestExecutionListener​

合并实现​​TestExecutionListener​

如果海关注册通过, 未注册默认侦听器。在最常见的测试场景中,这有效地 强制开发人员手动声明除任何自定义之外的所有默认侦听器 听众。下面的清单演示了这种配置方式:​​TestExecutionListener​​​​@TestExecutionListeners​

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

这种方法的挑战在于它要求开发人员确切地知道 默认情况下注册哪些侦听器。此外,默认侦听器集可以 从一个版本到另一个版本的变化 — 例如,是 在 Spring Framework 4.1 中引入,并在 Spring Framework 4.2 中引入。此外,像Spring这样的第三方框架 引导和 Spring 安全性通过使用上述自动发现机制注册自己的默认实现。​​SqlScriptsTestExecutionListener​​​​DirtiesContextBeforeModesTestExecutionListener​​​​TestExecutionListener​

为了避免必须知道并重新声明所有缺省侦听器,可以将属性 ofto。指示本地声明的侦听器应与 默认侦听器。合并算法可确保从 列表,并且根据语义对合并侦听器的结果集进行排序 的,如排序TestExecutionListener实现中所述。 如果侦听器实现者被注释,它可能会影响 与默认值合并的位置。否则,本地声明的侦听器 在合并时追加到默认侦听器列表中。​​mergeMode​​​​@TestExecutionListeners​​​​MergeMode.MERGE_WITH_DEFAULTS​​​​MERGE_WITH_DEFAULTS​​​​AnnotationAwareOrderComparator​​​​Ordered​​​​@Order​

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

@ContextConfiguration
@TestExecutionListeners(
listeners = MyCustomTestExecutionListener.class,
mergeMode = MERGE_WITH_DEFAULTS
)
class MyTest {
// class body...
}

3.5.4. 应用程序事件

从 Spring Framework 5.3.3 开始,TestContext 框架支持记录 中发布的应用程序事件,以便可以针对这些事件执行断言 测试。在执行单个测试期间发布的所有事件都通过以下方式提供 该 API,它允许您将事件处理为 a。​​ApplicationContext​​​​ApplicationEvents​​​​java.util.Stream​

要在测试中使用,请执行以下操作。​​ApplicationEvents​

  • 确保您的测试类带有注释或元注释@RecordApplicationEvents。
  • 确保已注册。但请注意, 这是默认注册的,只需要 如果您具有不包括默认侦听器的自定义配置,则手动注册。ApplicationEventsTestExecutionListenerApplicationEventsTestExecutionListener@TestExecutionListeners
  • 注释 typeWith 字段,并在测试和生命周期方法(例如 JUnit Jupiter 中的 andmethods)中使用该实例。ApplicationEvents@AutowiredApplicationEvents@BeforeEach@AfterEach
  • 当使用SpringExtension for JUnit Jupiter 时,你可以声明一个方法 类型参数在测试或生命周期方法中作为替代 到安菲尔德的测试课。ApplicationEvents@Autowired

以下测试类使用 for JUnit Jupiter 和AssertJ来断言应用程序事件的类型 在 Spring 管理的组件中调用方法时发布:​​SpringExtension​

@SpringJUnitConfig(/* ... */)
@RecordApplicationEvents
class OrderServiceTests {

@Autowired
OrderService orderService;

@Autowired
ApplicationEvents events;

@Test
void submitOrder() {
// Invoke method in OrderService that publishes an event
orderService.submitOrder(new Order(/* ... */));
// Verify that an OrderSubmitted event was published
long numEvents = events.stream(OrderSubmitted.class).count();
assertThat(numEvents).isEqualTo(1);
}
}

用注释测试类。​​@RecordApplicationEvents​

注入当前测试的实例。​​ApplicationEvents​

使用 API 计算发布了多少事件。​​ApplicationEvents​​​​OrderSubmitted​

请参阅ApplicationEventsjavadoc以获取有关 API 的更多详细信息。​​ApplicationEvents​

3.5.5. 测试执行事件

Spring Framework 5.2 中引入的 实现自定义的替代方法。组件在 test'scan 侦听以下事件,每个事件对应于 API 中的一个方法。​​EventPublishingTestExecutionListener​​​​TestExecutionListener​​​​ApplicationContext​​​​EventPublishingTestExecutionListener​​​​TestExecutionListener​

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

这些事件可能由于各种原因而被消耗,例如重置模拟 bean 或跟踪 测试执行。使用测试执行事件而不是实现测试执行事件的一个优点 测试执行事件可由任何 春豆在测试中注册,此类豆类可能会受益 直接来自依赖注入等功能。在 相比之下,AI不是豆子。​​TestExecutionListener​​​​ApplicationContext​​​​ApplicationContext​​​​TestExecutionListener​​​​ApplicationContext​

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

  • ​@BeforeTestClass​
  • ​@PrepareTestInstance​
  • ​@BeforeTestMethod​
  • ​@BeforeTestExecution​
  • ​@AfterTestExecution​
  • ​@AfterTestMethod​
  • ​@AfterTestClass​
异常处理

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

异步侦听器

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

3.5.6. 上下文管理

每个都为测试实例提供上下文管理和缓存支持 它对此负责。测试实例不会自动接收对 配置。但是,如果测试类实现了接口,则提供了对 到测试实例。请注意,并实现并且因此, 提供对自动的访问。​​TestContext​​​​ApplicationContext​​​​ApplicationContextAware​​​​ApplicationContext​​​​AbstractJUnit4SpringContextTests​​​​AbstractTestNGSpringContextTests​​​​ApplicationContextAware​​​​ApplicationContext​

使用 TestContext 框架的测试类不需要扩展任何特定的 类或实现特定接口以配置其应用程序上下文。相反 配置是通过在 班级级别。如果测试类未显式声明应用程序上下文资源 位置或组件类,配置确定如何加载 来自默认位置或默认配置类的上下文。除了上下文 资源位置和组件类,还可以配置应用程序上下文 通过应用程序上下文初始值设定项。​​@ContextConfiguration​​​​ContextLoader​

以下各节解释了如何使用 Spring'sannotation 来 通过使用 XML 配置文件、Groovy 脚本、 组件类(通常为类)或上下文初始值设定项。 或者,您可以实现和配置自己的自定义 高级用例。​​@ContextConfiguration​​​​ApplicationContext​​​​@Configuration​​​​SmartContextLoader​

  • 使用 XML 资源进行上下文配置
  • 使用时髦脚本进行上下文配置
  • 使用组件类进行上下文配置
  • 混合 XML、时髦脚本和组件类
  • 使用上下文初始值设定项进行上下文配置
  • 上下文配置继承
  • 使用环境配置文件进行上下文配置
  • 使用测试属性源进行上下文配置
  • 使用动态属性源进行上下文配置
  • 加载Web 应用程序上下文
  • 上下文缓存
  • 上下文层次结构
使用 XML 资源进行上下文配置

若要使用 XML 配置文件加载测试,请批注 您的测试类与并配置属性 一个数组,包含 XML 配置元数据的资源位置。平原或 相对路径(例如,)被视为类路径资源,即 相对于在其中定义测试类的包。以斜杠开头的路径 被视为绝对类路径位置(例如,)。一个 表示资源 URL(即前缀为,,,等的路径)的路径按原样使用。​​ApplicationContext​​​​@ContextConfiguration​​​​locations​​​​context.xml​​​​/org/example/config.xml​​​​classpath:​​​​file:​​​​http:​

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "/app-config.xml" and
// "/test-config.xml" in the root of the classpath
@ContextConfiguration(locations={"/app-config.xml", "/test-config.xml"})
class MyTest {
// class body...
}

将位置属性设置为 XML 文件列表。

​@ContextConfiguration​​通过 标准爪哇属性。因此,如果您不需要声明额外的 属性中,可以省略属性名称的声明,并使用速记格式声明资源位置 以下示例演示:​​locations​​​​value​​​​@ContextConfiguration​​​​locations​

@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-config.xml"})
class MyTest {
// class body...
}

指定 XML 文件而不使用属性。​​location​

如果从注释中省略了 theand 属性,则 TestContext 框架会尝试检测默认值 XML 资源位置。具体来说,并根据测试的名称检测默认位置 .class。如果您的类已命名,则加载您的 应用程序上下文来自。以下 示例显示了如何执行此操作:​​locations​​​​value​​​​@ContextConfiguration​​​​GenericXmlContextLoader​​​​GenericXmlWebContextLoader​​​​com.example.MyTest​​​​GenericXmlContextLoader​​​​"classpath:com/example/MyTest-context.xml"​

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTest-context.xml"
@ContextConfiguration
class MyTest {
// class body...
}

从默认位置加载配置。

使用时髦脚本进行上下文配置

若要使用使用Groovy Bean 定义 DSL 的 Groovy 脚本加载测试,可以注释 您的测试类使用包含 Groovy 脚本的资源位置的数组配置 theorAttribute 。资源 Groovy脚本的查找语义与XML配置文件的查找语义相同。​​ApplicationContext​​​​@ContextConfiguration​​​​locations​​​​value​

下面的示例演示如何指定 Groovy 配置文件:

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "/AppConfig.groovy" and
// "/TestConfig.groovy" in the root of the classpath
@ContextConfiguration({"/AppConfig.groovy", "/TestConfig.Groovy"})
class MyTest {
// class body...
}

指定 Groovy 配置文件的位置。

如果从注释中省略这两个属性,TestContext 框架会尝试检测默认的 Groovy 脚本。 具体来说,并根据测试类的名称检测默认位置。如果您的类已命名,则 Groovy 上下文加载器将从中加载应用程序上下文。以下示例演示如何使用 默认值:​​locations​​​​value​​​​@ContextConfiguration​​​​GenericGroovyXmlContextLoader​​​​GenericGroovyXmlWebContextLoader​​​​com.example.MyTest​​​​"classpath:com/example/MyTestContext.groovy"​

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTestContext.groovy"
@ContextConfiguration
class MyTest {
// class body...
}
使用组件类进行上下文配置

若要使用组件类加载测试(请参阅基于 Java 的容器配置),可以对测试进行批注 类与和配置属性与数组 包含对组件类的引用。以下示例演示如何执行此操作:​​ApplicationContext​​​​@ContextConfiguration​​​​classes​

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from AppConfig and TestConfig
@ContextConfiguration(classes = {AppConfig.class, TestConfig.class})
class MyTest {
// class body...
}

指定组件类。

如果从注释中省略属性, TestContext 框架尝试检测默认配置类的存在。 具体来说,并检测测试类中满足以下要求的所有嵌套类 配置类实现,如 @Configuration​javadoc 中指定。 请注意,配置类的名称是任意的。此外,测试类可以 如果需要,包含多个嵌套配置类。在下文中 示例,类声明嵌套配置类 命名自动用于加载测试的 .class:​​classes​​​​@ContextConfiguration​​​​AnnotationConfigContextLoader​​​​AnnotationConfigWebContextLoader​​​​static​​​​static​​​​OrderServiceTest​​​​static​​​​Config​​​​ApplicationContext​

@SpringJUnitConfig 
// ApplicationContext will be loaded from the
// static nested Config class
class OrderServiceTest {

@Configuration
static class Config {

// this bean will be injected into the OrderServiceTest class
@Bean
OrderService orderService() {
OrderService orderService = new OrderServiceImpl();
// set properties, etc.
return orderService;
}
}

@Autowired
OrderService orderService;

@Test
void testOrderService() {
// test the orderService
}

}


从嵌套类加载配置信息。​​Config​

混合 XML、时髦脚本和组件类

有时可能需要混合 XML 配置文件、Groovy 脚本和 组件类(通常为类)来配置测试。例如,如果在 生产,您可能决定要使用类来配置 用于测试的特定 Spring 管理组件,反之亦然。​​@Configuration​​​​ApplicationContext​​​​@Configuration​

此外,一些第三方框架(如Spring Boot)提供了一流的。 支持从不同类型的资源加载 同时(例如,XML 配置文件、Groovy 脚本和类)。从历史上看,Spring 框架不支持这一点 标准部署。因此,大多数实现 Spring 框架在模块中仅支持一种资源类型 对于每个测试上下文。但是,这并不意味着您不能同时使用两者。一 一般规则的例外是 theand支持 XML 配置文件和 Groovy。 同时编写脚本。此外,第三方框架可能会选择支持 声明和 标准测试支持 在测试上下文框架中,您有以下选项。​​ApplicationContext​​​​@Configuration​​​​SmartContextLoader​​​​spring-test​​​​GenericGroovyXmlContextLoader​​​​GenericGroovyXmlWebContextLoader​​​​locations​​​​classes​​​​@ContextConfiguration​

如果要使用资源位置(例如,XML 或 Groovy)和类来配置测试,则必须选择一个作为入口点,并且必须 包括或导入另一个。例如,在XML或Groovy脚本中,您可以通过使用组件扫描或将它们定义为普通的Spring来包含类。 bean,而在类中,您可以使用导入 XML 配置文件或 Groovy 脚本。请注意,此行为在语义上是等效的 有关如何在生产中配置应用程序:在生产配置中,您 定义一组 XML 或 Groovy 资源位置或一组从中加载产品的类,但您仍然拥有 *包含或导入其他类型的配置。​​@Configuration​​​​@Configuration​​​​@Configuration​​​​@ImportResource​​​​@Configuration​​​​ApplicationContext​

使用上下文初始值设定项进行上下文配置

若要使用上下文初始值设定项为测试配置, 注释您的测试类并使用包含对实现的类的引用的数组配置属性。然后,声明的上下文初始值设定项用于 初始化为您的测试加载的内容。请注意, 每个声明的初始值设定项支持的具体类型 必须与 的类型 创建 由 thein 使用(通常为 a)。此外, 初始化器的调用顺序取决于它们是实现 Spring 的接口还是使用 Spring 的 sannotation 或标准注释进行注释。下面的示例演示如何使用初始值设定项:​​ApplicationContext​​​​@ContextConfiguration​​​​initializers​​​​ApplicationContextInitializer​​​​ConfigurableApplicationContext​​​​ConfigurableApplicationContext​​​​ApplicationContext​​​​SmartContextLoader​​​​GenericApplicationContext​​​​Ordered​​​​@Order​​​​@Priority​

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from TestConfig
// and initialized by TestAppCtxInitializer
@ContextConfiguration(
classes = TestConfig.class,
initializers = TestAppCtxInitializer.class)
class MyTest {
// class body...
}

使用配置类和初始值设定项指定配置。

您还可以省略 XML 配置文件、Groovy 脚本或 组件类不完全,而是声明 only类,然后负责注册 bean 在上下文中 — 例如,通过以编程方式从 XML 加载 Bean 定义 文件或配置类。以下示例演示如何执行此操作:​​@ContextConfiguration​​​​ApplicationContextInitializer​

@ExtendWith(SpringExtension.class)
// ApplicationContext will be initialized by EntireAppInitializer
// which presumably registers beans in the context
@ContextConfiguration(initializers = EntireAppInitializer.class)
class MyTest {
// class body...
}

仅使用初始值设定项指定配置。

上下文配置继承

​@ContextConfiguration​​支持布尔和属性,这些属性表示资源位置还是组件类和上下文 超类声明的初始值设定项应继承。两者的默认值 旗帜是。这意味着测试类继承资源位置或 组件类以及任何超类声明的上下文初始值设定项。 具体而言,将追加测试类的资源位置或组件类 到资源位置或超类声明的批注类的列表。 同样,给定测试类的初始值设定项将添加到初始值设定项集中 由测试超类定义。因此,子类可以选择扩展资源 位置、组件类或上下文初始值设定项。​​inheritLocations​​​​inheritInitializers​​​​true​

如果 theorattribute inis 设置为,则资源位置或组件类和上下文 初始值设定项分别用于测试类的影子和有效替换 由超类定义的配置。​​inheritLocations​​​​inheritInitializers​​​​@ContextConfiguration​​​​false​

在下一个使用 XML 资源位置的示例中,foris 按该顺序加载自 and。 因此,定义为 incan 的 bean 会覆盖(即替换)那些 定义在。下面的示例演示一个类如何扩展 另一个,同时使用自己的配置文件和超类的配置文件:​​ApplicationContext​​​​ExtendedTest​​​​base-config.xml​​​​extended-config.xml​​​​extended-config.xml​​​​base-config.xml​

@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "/base-config.xml"
// in the root of the classpath
@ContextConfiguration("/base-config.xml")
class BaseTest {
// class body...
}

// ApplicationContext will be loaded from "/base-config.xml" and
// "/extended-config.xml" in the root of the classpath
@ContextConfiguration("/extended-config.xml")
class ExtendedTest extends BaseTest {
// class body...
}

在超类中定义的配置文件。

子类中定义的配置文件。

类似地,在下一个使用组件类的示例中,从 theandclasses 加载的 foris 在 次序。因此,定义为 incan 的 bean 覆盖(即替换) 那些定义在。下面的示例演示一个类如何扩展 另一个,并同时使用其自己的配置类和超类的配置类:​​ApplicationContext​​​​ExtendedTest​​​​BaseConfig​​​​ExtendedConfig​​​​ExtendedConfig​​​​BaseConfig​

// ApplicationContext will be loaded from BaseConfig
@SpringJUnitConfig(BaseConfig.class)
class BaseTest {
// class body...
}

// ApplicationContext will be loaded from BaseConfig and ExtendedConfig
@SpringJUnitConfig(ExtendedConfig.class)
class ExtendedTest extends BaseTest {
// class body...
}

在超类中定义的配置类。

在子类中定义的配置类。

在下一个使用上下文初始值设定项的示例中,foris 由 usingand 初始化。注意 但是,调用初始值设定项的顺序取决于它们是否 实现 Spring 的接口或用 Spring 的注释进行注释 或标准注释。下面的示例演示一个类如何 扩展另一个并使用其自己的初始值设定项和超类的初始值设定项:​​ApplicationContext​​​​ExtendedTest​​​​BaseInitializer​​​​ExtendedInitializer​​​​Ordered​​​​@Order​​​​@Priority​

// ApplicationContext will be initialized by BaseInitializer
@SpringJUnitConfig(initializers = BaseInitializer.class)
class BaseTest {
// class body...
}

// ApplicationContext will be initialized by BaseInitializer
// and ExtendedInitializer
@SpringJUnitConfig(initializers = ExtendedInitializer.class)
class ExtendedTest extends BaseTest {
// class body...
}

超类中定义的初始值设定项。

子类中定义的初始值设定项。

使用环境配置文件进行上下文配置

Spring 框架对环境和配置文件的概念具有一流的支持 (又名“Bean 定义配置文件”),并且可以配置集成测试以激活 适用于各种测试场景的特定 Bean 定义配置文件。这是通过 使用注释注释测试类并提供 加载测试时应激活的配置文件。​​@ActiveProfiles​​​​ApplicationContext​

考虑两个包含 XML 配置和类的示例:​​@Configuration​

<!-- app-config.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="...">

<bean
class="com.bank.service.internal.DefaultTransferService">
<constructor-arg ref="accountRepository"/>
<constructor-arg ref="feePolicy"/>
</bean>

<bean
class="com.bank.repository.internal.JdbcAccountRepository">
<constructor-arg ref="dataSource"/>
</bean>

<bean
class="com.bank.service.internal.ZeroFeePolicy"/>

<beans profile="dev">
<jdbc:embedded-database >
<jdbc:script
location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script
location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>

<beans profile="production">
<jee:jndi-lookup jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

<beans profile="default">
<jdbc:embedded-database >
<jdbc:script
location="classpath:com/bank/config/sql/schema.sql"/>
</jdbc:embedded-database>
</beans>

</beans>
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "classpath:/app-config.xml"
@ContextConfiguration("/app-config.xml")
@ActiveProfiles("dev")
class TransferServiceTest {

@Autowired
TransferService transferService;

@Test
void testTransferService() {
// test the transferService
}
}

运行时,它从类路径根目录中的配置文件加载。如果你检查,你可以看到thebean依赖于abean。但是,未定义为* Bean。相反,被定义三次:在配置文件中,在配置文件中, 并在个人资料中。​​TransferServiceTest​​​​ApplicationContext​​​​app-config.xml​​​​app-config.xml​​​​accountRepository​​​​dataSource​​​​dataSource​​​​dataSource​​​​production​​​​dev​​​​default​

通过注释,我们指导春天 测试上下文框架,以加载活动配置文件设置为。因此,将创建一个嵌入式数据库并填充测试数据,并且 Thebean与开发有关。 这可能是我们在集成测试中想要的。​​TransferServiceTest​​​​@ActiveProfiles("dev")​​​​ApplicationContext​​​​{"dev"}​​​​accountRepository​​​​DataSource​

有时将 bean 分配给配置文件很有用。默认内的 Bean 仅当未专门激活其他配置文件时,才会包含配置文件。您可以使用 这用于定义要在应用程序默认状态中使用的“回退”bean。为 例如,您可以显式提供数据源 forand配置文件, 但是,当内存中数据源都不是活动状态时,将内存中数据源定义为默认值。​​default​​​​dev​​​​production​

以下代码清单演示如何实现相同的配置和 使用类而不是 XML 进行集成测试:​​@Configuration​

@Configuration
@Profile("dev")
public class StandaloneDataConfig {

@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
@Configuration
@Profile("production")
public class JndiDataConfig {

@Bean(destroyMethod="")
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
@Configuration
@Profile("default")
public class DefaultDataConfig {

@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.build();
}
}
@Configuration
public class TransferServiceConfig {

@Autowired DataSource dataSource;

@Bean
public TransferService transferService() {
return new DefaultTransferService(accountRepository(), feePolicy());
}

@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}

@Bean
public FeePolicy feePolicy() {
return new ZeroFeePolicy();
}
}
@SpringJUnitConfig({
TransferServiceConfig.class,
StandaloneDataConfig.class,
JndiDataConfig.class,
DefaultDataConfig.class})
@ActiveProfiles("dev")
class TransferServiceTest {

@Autowired
TransferService transferService;

@Test
void testTransferService() {
// test the transferService
}
}

在此变体中,我们将 XML 配置拆分为四个独立的类:​​@Configuration​

  • ​TransferServiceConfig​​:通过使用依赖注入获取a。dataSource@Autowired
  • ​StandaloneDataConfig​​:为适用于 开发人员测试。dataSource
  • ​JndiDataConfig​​:定义在生产中从 JNDI 检索的内容 环境。dataSource
  • ​DefaultDataConfig​​:为默认嵌入式数据库定义 a,以防没有 配置文件处于活动状态。dataSource

与基于 XML 的配置示例一样,我们仍然进行注释,但这次我们通过以下方式指定所有四个配置类 使用注释。测试类本身的主体仍然存在 完全不变。​​TransferServiceTest​​​​@ActiveProfiles("dev")​​​​@ContextConfiguration​

通常情况下,跨多个测试类使用一组配置文件 在给定项目中。因此,为了避免重复的注释声明,您可以在基类和子类上声明一次 自动从基类继承配置。在 以下示例,声明(以及其他注释) 已移至抽象超类,:​​@ActiveProfiles​​​​@ActiveProfiles​​​​@ActiveProfiles​​​​@ActiveProfiles​​​​AbstractIntegrationTest​

// "dev" profile inherited from superclass
class TransferServiceTest extends AbstractIntegrationTest {

@Autowired
TransferService transferService;

@Test
void testTransferService() {
// test the transferService
}
}

​@ActiveProfiles​​还支持可用于 禁用活动配置文件的继承,如以下示例所示:​​inheritProfiles​

// "dev" profile overridden with "production"
@ActiveProfiles(profiles = "production", inheritProfiles = false)
class ProductionTransferServiceTest extends AbstractIntegrationTest {
// test body
}

此外,有时需要解析用于测试的活动配置文件 以编程方式而不是声明方式 — 例如,基于:

  • 当前操作系统。
  • 测试是否在持续集成生成服务器上运行。
  • 某些环境变量的存在。
  • 自定义类级批注的存在。
  • 其他问题。

要以编程方式解析活动的 Bean 定义概要文件,您可以实现 一个自定义并使用属性注册它。有关更多信息,请参阅相应的javadoc。 下面的示例演示如何实现和注册自定义:​​ActiveProfilesResolver​​​​resolver​​​​@ActiveProfiles​​​​OperatingSystemActiveProfilesResolver​

// "dev" profile overridden programmatically via a custom resolver
@ActiveProfiles(
resolver = OperatingSystemActiveProfilesResolver.class,
inheritProfiles = false)
class TransferServiceTest extends AbstractIntegrationTest {
// test body
}
public class OperatingSystemActiveProfilesResolver implements ActiveProfilesResolver {

@Override
public String[] resolve(Class<?> testClass) {
String profile = ...;
// determine the value of profile based on the operating system
return new String[] {profile};
}
}
使用测试属性源进行上下文配置

Spring 框架对具有 属性源的层次结构,您可以使用特定于测试的集成测试来配置 属性源。与类上使用的注释相反,您可以在测试上声明注释 类,用于声明测试属性文件或内联属性的资源位置。 这些测试属性源被添加到集合中 for 加载用于带注释的集成测试。​​@PropertySource​​​​@Configuration​​​​@TestPropertySource​​​​PropertySources​​​​Environment​​​​ApplicationContext​

声明测试属性源

可以使用 的理论属性配置测试属性文件。​​locations​​​​value​​​​@TestPropertySource​

支持传统和基于 XML 的属性文件格式,例如,OR。​​"classpath:/com/example/test.properties"​​​​"file:///path/to/file.xml"​

每条路径都被解释为一个弹簧。纯路径(例如)被视为相对于包的类路径资源 在其中定义测试类。以斜杠开头的路径被视为 绝对类路径资源(例如:)。一条路径 引用 URL(例如,前缀为 、、或的路径)是 使用指定的资源协议加载。不允许使用资源位置通配符(例如):每个位置的计算结果必须恰好为一个资源。​​Resource​​​​"test.properties"​​​​"/org/example/test.xml"​​​​classpath:​​​​file:​​​​http:​​​*/.properties​​​​.properties​​​​.xml​

下面的示例使用测试属性文件:

@ContextConfiguration
@TestPropertySource("/test.properties")
class MyIntegrationTests {
// class body...
}

指定具有绝对路径的属性文件。

您可以使用 的属性以键值对的形式配置内联属性,如下例所示。都 键值对作为单个测试以最高优先级添加到封闭中。​​properties​​​​@TestPropertySource​​​​Environment​​​​PropertySource​

键值对支持的语法与为 中的条目定义的语法相同 一个 Java 属性文件:

  • ​key=value​
  • ​key:value​
  • ​key value​

下面的示例设置两个内联属性:

@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port: 4242"})
class MyIntegrationTests {
// class body...
}

使用键值语法的两种变体设置两个属性。

默认属性文件检测

将 ifis 声明为空注释(即,没有显式 理论属性的值),尝试检测 相对于声明批注的类的默认属性文件。例如 如果带批注的测试类是,则相应的默认属性 文件是。如果无法检测到默认值,则抛出 anis。​​@TestPropertySource​​​​locations​​​​properties​​​​com.example.MyTest​​​​classpath:com/example/MyTest.properties​​​​IllegalStateException​

优先

测试属性的优先级高于操作系统中定义的优先级 环境、Java 系统属性或应用程序添加的属性源 通过使用或以编程方式以声明方式。因此,测试属性可以 用于有选择地重写从系统和应用程序属性加载的属性 来源。此外,内联属性的优先级高于加载的属性 从资源位置。但是请注意,通过以下方式注册的属性@DynamicPropertySource 优先级高于加载方式的优先级。​​@PropertySource​​​​@TestPropertySource​

在下一个示例中,定义的 andProperties 和任何属性将覆盖系统中定义的任何同名属性 和应用程序属性源。此外,如果文件定义 被内联覆盖的属性的条目 使用属性声明的属性。以下示例演示如何 在文件中和内联中指定属性:​​timezone​​​​port​​​​"/test.properties"​​​​"/test.properties"​​​​timezone​​​​port​​​​properties​

@ContextConfiguration
@TestPropertySource(
locations = "/test.properties",
properties = {"timezone = GMT", "port: 4242"}
)
class MyIntegrationTests {
// class body...
}
继承和重写测试属性源

​@TestPropertySource​​支持布尔属性,这些属性指示属性文件和内联的资源位置 超类声明的属性应该被继承。两个标志的默认值 是。这意味着测试类继承位置和内联属性 由任何超类声明。具体来说,位置和内联属性 测试类追加到超类声明的位置和内联属性。 因此,子类可以选择扩展位置和内联属性。注意 以后出现的属性阴影(即覆盖)同名的属性 出现较早。此外,上述优先规则适用于继承的 同时测试属性源。​​inheritLocations​​​​inheritProperties​​​​true​

如果理论属性 inis 设置为,分别是测试类的位置或内联属性 影子并有效地替换超类定义的配置。​​inheritLocations​​​​inheritProperties​​​​@TestPropertySource​​​​false​

在下一个示例中,仅使用文件作为测试属性源加载了 foris。相反,通过使用 theandfile 作为测试属性源位置来加载 foris。以下示例演示如何定义 子类及其超类中的属性 通过使用文件:​​ApplicationContext​​​​BaseTest​​​​base.properties​​​​ApplicationContext​​​​ExtendedTest​​​​base.properties​​​​extended.properties​​​​properties​

@TestPropertySource("base.properties")
@ContextConfiguration
class BaseTest {
// ...
}

@TestPropertySource("extended.properties")
@ContextConfiguration
class ExtendedTest extends BaseTest {
// ...
}

在下一个示例中,仅使用 内联属性。相比之下,福里斯 通过使用内联和属性加载。以下示例演示如何 使用内联属性定义子类及其超类中的属性:​​ApplicationContext​​​​BaseTest​​​​key1​​​​ApplicationContext​​​​ExtendedTest​​​​key1​​​​key2​

@TestPropertySource(properties = "key1 = value1")
@ContextConfiguration
class BaseTest {
// ...
}

@TestPropertySource(properties = "key2 = value2")
@ContextConfiguration
class ExtendedTest extends BaseTest {
// ...
}
使用动态属性源进行上下文配置

从Spring Framework 5.2.5开始,TestContext框架通过注释提供了对动态属性的支持。此注释可用于 需要将具有动态值的属性添加到集合中的集成测试,对于加载的 集成测试。​​@DynamicPropertySource​​​​PropertySources​​​​Environment​​​​ApplicationContext​

与在类级别应用的@TestPropertySource注释相反,必须应用 到接受单个参数的方法,该参数是 用于将名称-值对添加到。值是动态的,通过 athis 仅在解析属性时调用。通常,方法 引用用于提供值,如以下示例所示,该示例使用 Testcontainers 项目用于管理 Spring 之外的 Redis 容器。创建托管 Redis 容器的 IP 地址和端口 可用于测试中的组件通过和属性。这些属性可以通过 Spring 的抽象访问或直接注入到 Spring 管理的组件中 - 例如,分别通过。​@DynamicPropertySource​​​​static​​​​DynamicPropertyRegistry​​​​Environment​​​​Supplier​​​​ApplicationContext​​​​ApplicationContext​​​​redis.host​​​​redis.port​​​​Environment​​​​@Value("${redis.host}")​​​​@Value("${redis.port}")​

@SpringJUnitConfig(/* ... */)
@Testcontainers
class ExampleIntegrationTests {

@Container
static RedisContainer redis = new RedisContainer();

@DynamicPropertySource
static void redisProperties(DynamicPropertyRegistry registry) {
registry.add("redis.host", redis::getHost);
registry.add("redis.port", redis::getMappedPort);
}

// tests ...

}
优先

动态属性的优先级高于从中加载的属性, 操作系统的环境、Java 系统属性或由 添加的属性源 应用程序以声明方式使用或以编程方式。因此 动态属性可用于有选择地重写加载方式的属性、系统属性源和应用程序属性源。​​@TestPropertySource​​​​@PropertySource​​​​@TestPropertySource​

正在加载一个​​WebApplicationContext​

指示 TestContext 框架加载 a 而不是 标准,您可以使用注释相应的测试类。​​WebApplicationContext​​​​ApplicationContext​​​​@WebAppConfiguration​

测试类的存在指示测试上下文 框架 (TCF) 应该为您的 (WAC) 加载 集成测试。在后台,TCF 确保 创建并提供给测试的 WAC。默认情况下,您的基本资源路径设置为 。这被解释为路径相对 到 JVM 的根目录(通常是项目的路径)。如果您熟悉 Maven项目中Web应用程序的目录结构,您知道这是WAR根目录的默认位置。如果需要 覆盖此默认值,您可以提供注释的备用路径(例如,)。如果您愿意 从类路径而不是文件系统引用基资源路径,您可以使用 春天的前缀。​​@WebAppConfiguration​​​​WebApplicationContext​​​​MockServletContext​​​​MockServletContext​​​​src/main/webapp​​​​src/main/webapp​​​​@WebAppConfiguration​​​​@WebAppConfiguration("src/test/webapp")​​​​classpath:​

请注意,Spring 对实现的测试支持是相当的 支持标准实现。使用 a 进行测试时,您可以*声明 XML 配置文件、Groovy 脚本、 或使用类。您也可以免费使用 任何其他测试注释,例如,,,,等。​​WebApplicationContext​​​​ApplicationContext​​​​WebApplicationContext​​​​@Configuration​​​​@ContextConfiguration​​​​@ActiveProfiles​​​​@TestExecutionListeners​​​​@Sql​​​​@Rollback​

本节中的其余示例显示了 加载 a.以下示例显示了测试上下文 框架对约定重于配置的支持:​​WebApplicationContext​

@ExtendWith(SpringExtension.class)

// defaults to "file:src/main/webapp"
@WebAppConfiguration

// detects "WacTests-context.xml" in the same package
// or static nested @Configuration classes
@ContextConfiguration
class WacTests {
//...
}

如果在未指定资源的情况下批注测试类 基路径,则资源路径实际上默认为。同样地 如果您在没有指定资源、组件或上下文的情况下声明,Spring 会尝试检测是否存在 使用约定(即在同一包中)进行配置 作为类或静态嵌套类)。​​@WebAppConfiguration​​​​file:src/main/webapp​​​​@ContextConfiguration​​​​locations​​​​classes​​​​initializers​​​​WacTests-context.xml​​​​WacTests​​​​@Configuration​

下面的示例演示如何使用以下内容显式声明资源基路径和 XML 资源位置:​​@WebAppConfiguration​​​​@ContextConfiguration​

@ExtendWith(SpringExtension.class)

// file system resource
@WebAppConfiguration("webapp")

// classpath resource
@ContextConfiguration("/spring/test-servlet-config.xml")
class WacTests {
//...
}

这里要注意的重要一点是具有这两个路径的不同语义 附注。默认情况下,资源路径是基于文件系统的, 而资源位置是基于类路径的。​​@WebAppConfiguration​​​​@ContextConfiguration​

下面的示例演示我们可以覆盖两者的默认资源语义 通过指定 Spring 资源前缀进行注释:

@ExtendWith(SpringExtension.class)

// classpath resource
@WebAppConfiguration("classpath:test-web-resources")

// file system resource
@ContextConfiguration("file:src/main/webapp/WEB-INF/servlet-config.xml")
class WacTests {
//...
}

将此示例中的注释与上一示例中的注释进行对比。

使用 Web 模拟

为了提供全面的 Web 测试支持,TestContext 框架默认启用。当针对 a 进行测试时,此TestExecutionListener使用 Spring Web 的 before 设置默认的线程本地状态 每个测试方法并创建一个、A 和 a基于配置的基本资源路径。还确保 THE AND 可以注入到测试实例中, 并且,一旦测试完成,它将清理线程本地状态。​​ServletTestExecutionListener​​​​WebApplicationContext​​​​RequestContextHolder​​​​MockHttpServletRequest​​​​MockHttpServletResponse​​​​ServletWebRequest​​​​@WebAppConfiguration​​​​ServletTestExecutionListener​​​​MockHttpServletResponse​​​​ServletWebRequest​

加载测试后,您可能会发现 需要与网络模拟进行交互 — 例如,设置测试装置或 在调用 Web 组件后执行断言。以下示例显示哪个 模拟可以自动连接到测试实例中。请注意,theand都是缓存在测试套件中,而其他模拟是 按测试方法管理。​​WebApplicationContext​​​​WebApplicationContext​​​​MockServletContext​​​​ServletTestExecutionListener​

@SpringJUnitWebConfig
class WacTests {

@Autowired
WebApplicationContext wac; // cached

@Autowired
MockServletContext servletContext; // cached

@Autowired
MockHttpSession session;

@Autowired
MockHttpServletRequest request;

@Autowired
MockHttpServletResponse response;

@Autowired
ServletWebRequest webRequest;

//...
}
上下文缓存

一旦 TestContext 框架加载了一个(或) 对于测试,该上下文将被缓存并重用于声明 同一测试套件中具有相同的唯一上下文配置。了解缓存方式 工作,重要的是要理解“唯一”和“测试套件”的含义。​​ApplicationContext​​​​WebApplicationContext​

Ancan 通过配置组合唯一标识 用于加载它的参数。因此,独特的配置组合 参数用于生成缓存上下文的键。测试上下文 框架使用以下配置参数来构建上下文缓存键:​​ApplicationContext​

  • ​locations​​(来自@ContextConfiguration)
  • ​classes​​(来自@ContextConfiguration)
  • ​contextInitializerClasses​​(来自@ContextConfiguration)
  • ​contextCustomizers​​(from) – 这包括Spring Boot的方法以及各种功能 测试支持,如桑德。ContextCustomizerFactory@DynamicPropertySource@MockBean@SpyBean
  • ​contextLoader​​(来自@ContextConfiguration)
  • ​parent​​(来自@ContextHierarchy)
  • ​activeProfiles​​(来自@ActiveProfiles)
  • ​propertySourceLocations​​(来自@TestPropertySource)
  • ​propertySourceProperties​​(来自@TestPropertySource)
  • ​resourceBasePath​​(来自@WebAppConfiguration)

例如,ifspecifiesfor 的(或)属性,TestContext 框架 加载相应的内容并将其存储在上下文缓存中 在仅基于这些位置的密钥下。因此,if也定义了它的位置(显式或 隐式通过继承)但不定义不同的、不同的活动配置文件、不同的上下文初始值设定项、不同的 测试属性源或不同的父上下文,则 sameis 由两个测试类共享。这意味着加载应用程序的设置成本 上下文仅发生一次(每个测试套件),后续测试执行很多 更快。​​TestClassA​​​​{"app-config.xml", "test-config.xml"}​​​​locations​​​​value​​​​@ContextConfiguration​​​​ApplicationContext​​​​static​​​​TestClassB​​​​{"app-config.xml", "test-config.xml"}​​​​@WebAppConfiguration​​​​ContextLoader​​​​ApplicationContext​

上下文缓存的大小以默认的最大大小 32 为界。每当 达到最大大小,使用最近最少使用 (LRU) 逐出策略来逐出和 关闭过时的上下文。您可以从命令行或内部版本配置最大大小 脚本,通过设置名为 JVM 系统属性。作为一个 或者,您可以通过SpringProperties​机制设置相同的属性。​​spring.test.context.cache.maxSize​

由于在给定的测试套件中加载大量应用程序上下文可以 导致套件运行不必要的长时间,这通常是有益的 确切地知道已加载和缓存的上下文数。查看 的统计信息 对于基础上下文缓存,可以将日志记录类别的日志级别设置为 。​​org.springframework.test.context.cache​​​​DEBUG​

在极少数情况下,测试会损坏应用程序上下文并需要重新加载 (例如,通过修改 Bean 定义或应用程序对象的状态),您可以 可以注释您的测试类或测试方法(请参阅春季测试中的讨论 注释)。这指示 Spring 从缓存中删除上下文并重建 运行下一个需要相同应用程序的测试之前的应用程序上下文 上下文。请注意,对注释的支持由 theand 提供,默认情况下处于启用状态。​​@DirtiesContext​​​​@DirtiesContext​​​​@DirtiesContext​​​​DirtiesContextBeforeModesTestExecutionListener​​​​DirtiesContextTestExecutionListener​

上下文层次结构

在编写依赖于加载的 Spring 的集成测试时,它是 通常足以针对单个上下文进行测试。但是,有时它是 对针对实例层次结构进行测试是有益的,甚至是必要的。例如,如果您正在开发Spring MVC Web应用程序,则通常 有根被春天的沙子 被春天的孩子装了。这导致 父子上下文层次结构,其*享组件和基础结构配置 在根上下文中声明,并由特定于 Web 的在子上下文中使用 组件。另一个用例可以在Spring Batch应用程序中找到,您经常在其中 具有为共享批处理基础结构提供配置的父上下文和 用于配置特定批处理作业的子上下文。​​ApplicationContext​​​​ApplicationContext​​​​WebApplicationContext​​​​ContextLoaderListener​​​​WebApplicationContext​​​​DispatcherServlet​

您可以通过声明上下文来编写使用上下文层次结构的集成测试 在单个测试类上使用注释进行配置 或在测试类层次结构中。如果在多个类上声明了上下文层次结构 在测试类层次结构中,还可以合并或覆盖上下文配置 对于上下文层次结构中的特定命名级别。合并 的配置时 层次结构中的给定级别,配置资源类型(即 XML 配置 文件或组件类)必须一致。否则,完全可以接受 在使用不同资源类型配置的上下文层次结构中具有不同的级别。​​@ContextHierarchy​

本节中其余基于 JUnit Jupiter 的示例显示了常见配置 需要使用上下文层次结构的集成测试方案。

具有上下文层次结构的单个测试类

​ControllerIntegrationTests​​表示 Spring MVC Web 应用程序通过声明由两个级别组成的上下文层次结构, 一个用于根(通过使用类加载),一个用于调度程序 servlet(通过使用类加载)。自动连接到测试实例的是子上下文(即 层次结构中的最低上下文)。以下清单显示了此配置方案:​​WebApplicationContext​​​​TestAppConfig​​​​@Configuration​​​​WebApplicationContext​​​​WebConfig​​​​@Configuration​​​​WebApplicationContext​

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = TestAppConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class ControllerIntegrationTests {

@Autowired
WebApplicationContext wac;

// ...
}

具有隐式父上下文的类层次结构

此示例中的测试类定义测试类中的上下文层次结构 hierarchy.声明根在 Spring 驱动的 Web 应用程序中的配置。但是请注意,这并没有声明。因此,子类可以选择参与上下文层次结构或遵循 标准语义 和 扩展 定义上下文层次结构 用。结果是加载了三个应用程序上下文(一个 对于 的每个声明),以及加载的应用程序上下文 基于配置为每个 为具体子类加载的上下文。以下清单显示了这一点 配置方案:​​AbstractWebTests​​​​WebApplicationContext​​​​AbstractWebTests​​​​@ContextHierarchy​​​​AbstractWebTests​​​​@ContextConfiguration​​​​SoapWebServiceTests​​​​RestWebServiceTests​​​​AbstractWebTests​​​​@ContextHierarchy​​​​@ContextConfiguration​​​​AbstractWebTests​

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
public abstract class AbstractWebTests {}

@ContextHierarchy(@ContextConfiguration("/spring/soap-ws-config.xml"))
public class SoapWebServiceTests extends AbstractWebTests {}

@ContextHierarchy(@ContextConfiguration("/spring/rest-ws-config.xml"))
public class RestWebServiceTests extends AbstractWebTests {}

具有合并上下文层次结构配置的类层次结构

此示例中的类显示了如何使用命名层次结构级别来合并 上下文层次结构中特定级别的配置。定义两个级别 在层次结构中,和.扩展和指示 Spring TestContext 框架通过确保属性中声明的名称同时存在两者来合并层次结构级别的上下文配置。结果是三个应用程序上下文 已加载:一个用于、一个用于和一个用于。与前面的示例一样, 加载自的应用程序上下文设置为父上下文 加载自的上下文。 以下清单显示了此配置方案:​​BaseTests​​​​parent​​​​child​​​​ExtendedTests​​​​BaseTests​​​​child​​​​name​​​​@ContextConfiguration​​​​child​​​​/app-config.xml​​​​/user-config.xml​​​​{"/user-config.xml", "/order-config.xml"}​​​​/app-config.xml​​​​/user-config.xml​​​​{"/user-config.xml", "/order-config.xml"}​

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(name = "parent", locations = "/app-config.xml"),
@ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}

@ContextHierarchy(
@ContextConfiguration(name = "child", locations = "/order-config.xml")
)
class ExtendedTests extends BaseTests {}

具有重写上下文层次结构配置的类层次结构

与前面的示例相比,此示例演示了如何重写 通过设置 Flag 为 在上下文层次结构中配置给定命名级别。因此, 应用程序上下文 foris 仅从和加载 将其父级设置为从中加载的上下文。以下列表 显示了以下配置方案:​​inheritLocations​​​​@ContextConfiguration​​​​false​​​​ExtendedTests​​​​/test-user-config.xml​​​​/app-config.xml​

@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(name = "parent", locations = "/app-config.xml"),
@ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}

@ContextHierarchy(
@ContextConfiguration(
name = "child",
locations = "/test-user-config.xml",
inheritLocations = false
))
class ExtendedTests extends BaseTests {}