The Spring TestContext Framework (located in the org.springframework.test.context package) provides generic,
annotation-driven unit and integration testing support that is agnostic of the testing framework in use.
Spring 测试上下文框架(位于 org.springframework.test.context
包中)提供通用的、基于注解的单元和集成测试支持,与使用的测试框架无关。
The TestContext framework also places a great deal of importance on convention over configuration, with reasonable
defaults that you can override through annotation-based configuration.
测试上下文框架也非常重视约定优于配置,提供合理的默认设置,您可以通过基于注解的配置来覆盖这些设置。
In addition to generic testing infrastructure, the TestContext framework provides explicit support for JUnit 4, JUnit
Jupiter (AKA JUnit 5), and TestNG. For JUnit 4 and TestNG, Spring provides abstract support classes. Furthermore,
Spring provides a custom JUnit Runner and custom JUnit Rules for JUnit 4 and a custom Extension for JUnit Jupiter
that let you write so-called POJO test classes. POJO test classes are not required to extend a particular class
hierarchy, such as the abstract support classes.
除了通用的测试基础设施之外,TestContext 框架提供了对 JUnit 4、JUnit Jupiter(又称 JUnit 5)和 TestNG 的明确支持。对于 JUnit 4
和 TestNG,Spring 提供了 abstract 支持类。此外,Spring 为 JUnit 4 提供了自定义 JUnit Runner 和自定义 JUnit Rules ,并为
JUnit Jupiter 提供了自定义 Extension ,让您能够编写所谓的 POJO 测试类。POJO 测试类不需要扩展特定的类层次,例如 abstract
支持类。
The following section provides an overview of the internals of the TestContext framework. If you are interested only in
using the framework and are not interested in extending it with your own custom listeners or custom loaders, feel free
to go directly to the
configuration (context management, dependency injection, transaction management), support classes,
and annotation support sections.
以下部分提供了 TestContext 框架内部的概述。如果您只对使用该框架感兴趣,而不想通过自己的自定义监听器或自定义加载器来扩展它,请直接跳转到配置(上下文管理、依赖注入、事务管理)、支持类和注解支持部分。
The core of the framework consists of the TestContextManager class and the TestContext, TestExecutionListener, and
SmartContextLoader interfaces. A TestContextManager is created for each test class (for example, for the execution
of all test methods within a single test class in JUnit Jupiter). The TestContextManager, in turn, manages a
TestContext that holds the context of the current test. The TestContextManager also updates the state of the
TestContext as the test progresses and delegates to TestExecutionListener implementations, which instrument the
actual test execution by providing dependency injection, managing transactions, and so on. A SmartContextLoader is
responsible for loading an ApplicationContext for a given test class. See
the javadoc
and the Spring test suite for further information and examples of various implementations.
框架的核心包括 TestContextManager 类和 TestContext 、 TestExecutionListener 、 SmartContextLoader 接口。为每个测试类创建一个
TestContextManager (例如,在 JUnit Jupiter 中执行单个测试类内的所有测试方法)。 TestContextManager 反过来管理一个包含当前测试上下文的
TestContext 。 TestContextManager 在测试进行过程中更新 TestContext 的状态,并将任务委托给 TestExecutionListener
实现,这些实现通过提供依赖注入、管理事务等来对实际测试执行进行配置。 SmartContextLoader 负责为给定的测试类加载一个
ApplicationContext 。有关更多信息和各种实现的示例,请参阅 javadoc 和 Spring 测试套件。
TestContextTestContext encapsulates the context in which a test is run (agnostic of the actual testing framework in use) and
provides context management and caching support for the test instance for which it is responsible. The TestContext
also delegates to a SmartContextLoader to load an ApplicationContext if requested.
TestContext 封装了测试运行的上下文(与实际使用的测试框架无关)并为它负责的测试实例提供上下文管理和缓存支持。
TestContext 还委托给 SmartContextLoader 来加载 ApplicationContext (如果需要的话)。
TestContextManagerTestContextManager is the main entry point into the Spring TestContext Framework and is responsible for managing a
single TestContext and signaling events to each registered TestExecutionListener at well-defined test execution
points:
TestContextManager 是 Spring TestContext 框架的主要入口点,负责管理单个 TestContext 并在定义良好的测试执行点向每个注册的
TestExecutionListener 发出信号:
Prior to any “before class” or “before all” methods of a particular testing framework.
在特定测试框架的任何“课前”或“全部之前”方法之前。
Test instance post-processing.
测试实例后处理。
Prior to any “before” or “before each” methods of a particular testing framework.
在特定测试框架的任何“before”或“before each”方法之前。
Immediately before execution of the test method but after test setup.
立即在执行测试方法之前,但在测试设置之后。
Immediately after execution of the test method but before test tear down.
立即在执行测试方法之后但在测试清理之前。
After any “after” or “after each” methods of a particular testing framework.
在特定测试框架的任何“after”或“after each”方法之后。
After any “after class” or “after all” methods of a particular testing framework.
在特定测试框架的“课后”或“毕竟”方法之后。
TestExecutionListenerTestExecutionListener defines the API for reacting to test-execution events published by the TestContextManager with
which the listener is registered. See TestExecutionListener Configuration.
TestExecutionListener 定义了由与监听器注册的 TestContextManager 发布的测试执行事件的响应 API。请参阅
TestExecutionListener 配置。
ContextLoader is a strategy interface for loading an ApplicationContext for an integration test managed by the
Spring TestContext Framework. You should implement SmartContextLoader instead of this interface to provide support for
component classes, active bean definition profiles, test property sources, context hierarchies, and
WebApplicationContext support.
ContextLoader 是 Spring TestContext Framework 管理的集成测试中加载 ApplicationContext 的策略接口。您应该实现
SmartContextLoader 而不是此接口,以提供对组件类、活动 Bean 定义配置文件、测试属性源、上下文层次结构以及
WebApplicationContext 支持的支撑。
SmartContextLoader is an extension of the ContextLoader interface that supersedes the original minimal
ContextLoader SPI. Specifically, a SmartContextLoader can choose to process resource locations, component classes,
or context initializers. Furthermore, a SmartContextLoader can set active bean definition profiles and test property
sources in the context that it loads.
SmartContextLoader 是 ContextLoader 接口的扩展,取代了原始的最小 ContextLoader SPI。具体来说,一个
SmartContextLoader 可以选择处理资源位置、组件类或上下文初始化器。此外,一个 SmartContextLoader 可以设置激活的 bean
定义配置文件并在它加载的上下文中测试属性源。
Spring provides the following implementations:
Spring 提供了以下实现:
DelegatingSmartContextLoader: One of two default loaders, it delegates internally to an
AnnotationConfigContextLoader, a GenericXmlContextLoader, or a GenericGroovyXmlContextLoader, depending either
on the configuration declared for the test class or on the presence of default locations or default configuration
classes. Groovy support is enabled only if Groovy is on the classpath.
DelegatingSmartContextLoader :两个默认加载器之一,它内部委托给一个 AnnotationConfigContextLoader 、一个
GenericXmlContextLoader 或一个 GenericGroovyXmlContextLoader ,具体取决于测试类的声明配置、默认位置或默认配置类。只有当
Groovy 在类路径上时,Groovy 支持才被启用。
WebDelegatingSmartContextLoader: One of two default loaders, it delegates internally to an
AnnotationConfigWebContextLoader, a GenericXmlWebContextLoader, or a GenericGroovyXmlWebContextLoader, depending
either on the configuration declared for the test class or on the presence of default locations or default
configuration classes. A web ContextLoader is used only if @WebAppConfiguration is present on the test class.
Groovy support is enabled only if Groovy is on the classpath.
WebDelegatingSmartContextLoader :两个默认加载器之一,它内部委托给一个 AnnotationConfigWebContextLoader 、一个
GenericXmlWebContextLoader 或一个 GenericGroovyXmlWebContextLoader ,具体取决于测试类的声明配置或默认位置或默认配置类的存在。只有当测试类上存在
@WebAppConfiguration 时,才使用 Web ContextLoader 。只有当 Groovy 在类路径上时,Groovy 支持才启用。
AnnotationConfigContextLoader: Loads a standard ApplicationContext from component classes.
AnnotationConfigContextLoader :从组件类中加载标准 ApplicationContext 。
AnnotationConfigWebContextLoader: Loads a WebApplicationContext from component classes.
AnnotationConfigWebContextLoader :从组件类中加载 WebApplicationContext 。
GenericGroovyXmlContextLoader: Loads a standard ApplicationContext from resource locations that are either Groovy
scripts or XML configuration files.
GenericGroovyXmlContextLoader :从资源位置加载标准 ApplicationContext ,这些位置可以是 Groovy 脚本或 XML 配置文件。
GenericGroovyXmlWebContextLoader: Loads a WebApplicationContext from resource locations that are either Groovy
scripts or XML configuration files.
GenericGroovyXmlWebContextLoader :从资源位置加载 WebApplicationContext ,这些位置可以是 Groovy 脚本或 XML 配置文件。
GenericXmlContextLoader: Loads a standard ApplicationContext from XML resource locations.
GenericXmlContextLoader :从 XML 资源位置加载标准 ApplicationContext 。
GenericXmlWebContextLoader: Loads a WebApplicationContext from XML resource locations.
GenericXmlWebContextLoader :从 XML 资源位置加载 WebApplicationContext 。
3.5.2. 引入 TestContext 框架
The default configuration for the internals of the Spring TestContext Framework is sufficient for all common use cases.
However, there are times when a development team or third party framework would like to change the default
ContextLoader, implement a custom TestContext or ContextCache, augment the default sets of
ContextCustomizerFactory and TestExecutionListener implementations, and so on. For such low-level control over how
the TestContext framework operates, Spring provides a bootstrapping strategy.
Spring TestContext 框架内部的默认配置适用于所有常见用例。然而,有时开发团队或第三方框架可能希望更改默认配置
ContextLoader ,实现自定义 TestContext 或 ContextCache ,增强默认的 ContextCustomizerFactory 和
TestExecutionListener 实现集,等等。为了对 TestContext 框架的操作进行低级别控制,Spring 提供了一种引导策略。
TestContextBootstrapper defines the SPI for bootstrapping the TestContext framework. A TestContextBootstrapper is
used by the TestContextManager to load the TestExecutionListener implementations for the current test and to build
the TestContext that it manages. You can configure a custom bootstrapping strategy for a test class (or test class
hierarchy) by using @BootstrapWith, either directly or as a meta-annotation. If a bootstrapper is not explicitly
configured by using @BootstrapWith, either the DefaultTestContextBootstrapper or the WebTestContextBootstrapper is
used, depending on the presence of @WebAppConfiguration.
TestContextBootstrapper 定义了用于启动 TestContext 框架的 SPI。 TestContextBootstrapper 被用于加载当前测试的
TestExecutionListener 实现,并构建它所管理的 TestContext 。您可以通过使用 @BootstrapWith
来为测试类(或测试类层次结构)配置自定义启动策略,无论是直接使用还是作为元注解。如果没有使用 @BootstrapWith 明确配置启动器,则根据
@WebAppConfiguration 的存在与否,使用 DefaultTestContextBootstrapper 或 WebTestContextBootstrapper 。
Since the TestContextBootstrapper SPI is likely to change in the future (to accommodate new requirements), we strongly
encourage implementers not to implement this interface directly but rather to extend AbstractTestContextBootstrapper
or one of its concrete subclasses instead.
由于 TestContextBootstrapper SPI 可能会在未来发生变化(以适应新的需求),我们强烈建议实施者不要直接实现此接口,而是扩展
AbstractTestContextBootstrapper 或其具体子类之一。
TestExecutionListener Configuration 3.5.3.TestExecutionListener 配置Spring provides the following TestExecutionListener implementations that are registered by default, exactly in the
following order:
Spring 提供了以下默认注册的实现,顺序如下:
ServletTestExecutionListener: Configures Servlet API mocks for a WebApplicationContext.
ServletTestExecutionListener :为 WebApplicationContext 配置 Servlet API 模拟
DirtiesContextBeforeModesTestExecutionListener: Handles the @DirtiesContext annotation for “before” modes.
DirtiesContextBeforeModesTestExecutionListener :处理“之前”模式的 @DirtiesContext 注解。
ApplicationEventsTestExecutionListener: Provides support for
ApplicationEvents.
ApplicationEventsTestExecutionListener :为 ApplicationEvents 提供支持。
DependencyInjectionTestExecutionListener: Provides dependency injection for the test instance.
DependencyInjectionTestExecutionListener : 为测试实例提供依赖注入。
DirtiesContextTestExecutionListener: Handles the @DirtiesContext annotation for “after” modes.
DirtiesContextTestExecutionListener : 处理“after”模式的 @DirtiesContext 注解。
TransactionalTestExecutionListener: Provides transactional test execution with default rollback semantics.
提供具有默认回滚语义的事务性测试执行。
SqlScriptsTestExecutionListener: Runs SQL scripts configured by using the @Sql annotation.
SqlScriptsTestExecutionListener : 使用 @Sql 注解运行配置的 SQL 脚本。
EventPublishingTestExecutionListener: Publishes test execution events to the test’s ApplicationContext (
see Test Execution Events).
EventPublishingTestExecutionListener :将测试执行事件发布到测试的 ApplicationContext (见测试执行事件)。
TestExecutionListener Implementations注册 TestExecutionListener 实现
You can register TestExecutionListener implementations explicitly for a test class, its subclasses, and its nested
classes by using the @TestExecutionListeners annotation. See annotation support
and the javadoc for
@TestExecutionListeners
for details and examples.
您可以通过使用 @TestExecutionListeners 注解显式地为测试类、其子类和嵌套类注册 TestExecutionListener
实现。有关详细信息和方法示例,请参阅 @TestExecutionListeners 的注解支持和 javadoc。
Switching to default TestExecutionListener implementations
切换到默认 TestExecutionListener 实现
If you extend a class that is annotated with @TestExecutionListeners and you need to switch to using the default set
of listeners, you can annotate your class with the following.
如果您扩展了一个被 @TestExecutionListeners 注解的类,并且需要切换到使用默认的监听器集,您可以使用以下注解来注解您的类。
TestExecutionListener Implementations自动发现默认 TestExecutionListener 实现
Registering TestExecutionListener implementations by using @TestExecutionListeners is suitable for custom listeners
that are used in limited testing scenarios. However, it can become cumbersome if a custom listener needs to be used
across an entire test suite. This issue is addressed through support for automatic discovery of default
TestExecutionListener implementations through the SpringFactoriesLoader mechanism.
使用 @TestExecutionListeners 注册 TestExecutionListener
实现适用于在有限测试场景中使用的自定义监听器。然而,如果需要在整个测试套件中使用自定义监听器,这可能会变得繁琐。通过支持通过
SpringFactoriesLoader 机制自动发现默认 TestExecutionListener 实现,解决了这个问题。
Specifically, the spring-test module declares all core default TestExecutionListener implementations under the
org.springframework.test.context.TestExecutionListener key in its META-INF/spring.factories properties file.
Third-party frameworks and developers can contribute their own TestExecutionListener implementations to the list of
default listeners in the same manner through their own META-INF/spring.factories properties file.
具体来说, spring-test 模块在其 META-INF/spring.factories 属性文件下通过
org.springframework.test.context.TestExecutionListener 键声明了所有核心默认 TestExecutionListener
实现。第三方框架和开发者可以通过自己的 META-INF/spring.factories 属性文件以相同的方式向默认监听器列表贡献自己的
TestExecutionListener 实现。
TestExecutionListener Implementations订购 TestExecutionListener 实现
When the TestContext framework discovers default TestExecutionListener implementations through
the aforementioned SpringFactoriesLoader mechanism, the instantiated
listeners are sorted by using Spring’s AnnotationAwareOrderComparator, which honors Spring’s Ordered interface and
@Order annotation for ordering. AbstractTestExecutionListener and all default TestExecutionListener
implementations provided by Spring implement Ordered with appropriate values. Third-party frameworks and developers
should therefore make sure that their default TestExecutionListener implementations are registered in the proper order
by implementing Ordered or declaring @Order. See the javadoc for the getOrder() methods of the core default
TestExecutionListener implementations for details on what values are assigned to each core listener.
当 TestContext 框架通过上述机制发现默认 TestExecutionListener 实现时,将使用 Spring 的 AnnotationAwareOrderComparator
对实例化的监听器进行排序,该机制尊重 Spring 的 Ordered 接口和 @Order 注解以进行排序。 AbstractTestExecutionListener
以及 Spring 提供的所有默认 TestExecutionListener 实现都实现了 Ordered ,并赋予适当的值。因此,第三方框架和开发者应确保通过实现
Ordered 或声明 @Order ,以正确的顺序注册它们的默认 TestExecutionListener 实现。有关分配给每个核心监听器的值的详细信息,请参阅核心默认
TestExecutionListener 实现的 getOrder() 方法的 javadoc。
TestExecutionListener Implementations合并 TestExecutionListener 实现
If a custom TestExecutionListener is registered via @TestExecutionListeners, the default listeners are not
registered. In most common testing scenarios, this effectively forces the developer to manually declare all default
listeners in addition to any custom listeners. The following listing demonstrates this style of configuration:
如果通过 @TestExecutionListeners 注册自定义 TestExecutionListener
,则不会注册默认监听器。在大多数常见的测试场景中,这实际上迫使开发者除了任何自定义监听器外,还必须手动声明所有默认监听器。以下列表展示了这种配置方式:
The challenge with this approach is that it requires that the developer know exactly which listeners are registered by
default. Moreover, the set of default listeners can change from release to release — for example,
SqlScriptsTestExecutionListener was introduced in Spring Framework 4.1, and
DirtiesContextBeforeModesTestExecutionListener was introduced in Spring Framework 4.2. Furthermore, third-party
frameworks like Spring Boot and Spring Security register their own default TestExecutionListener implementations by
using the aforementioned automatic discovery mechanism.
这种方法的挑战在于,它要求开发者确切知道默认注册了哪些监听器。此外,默认监听器的集合可能会随着版本的不同而变化——例如,
SqlScriptsTestExecutionListener 是在 Spring Framework 4.1 中引入的,而 DirtiesContextBeforeModesTestExecutionListener
是在 Spring Framework 4.2 中引入的。此外,像 Spring Boot 和 Spring Security 这样的第三方框架通过使用上述自动发现机制,注册它们自己的默认
TestExecutionListener 实现。
To avoid having to be aware of and re-declare all default listeners, you can set the mergeMode attribute of
@TestExecutionListeners to MergeMode.MERGE_WITH_DEFAULTS. MERGE_WITH_DEFAULTS indicates that locally declared
listeners should be merged with the default listeners. The merging algorithm ensures that duplicates are removed from
the list and that the resulting set of merged listeners is sorted according to the semantics of
AnnotationAwareOrderComparator, as described in Ordering
TestExecutionListener Implementations. If a listener implements Ordered or is
annotated with @Order, it can influence the position in which it is merged with the defaults. Otherwise, locally
declared listeners are appended to the list of default listeners when merged.
为了避免需要知道并重新声明所有默认监听器,可以将 @TestExecutionListeners 的 mergeMode 属性设置为
MergeMode.MERGE_WITH_DEFAULTS 。 MERGE_WITH_DEFAULTS 表示本地声明的监听器应与默认监听器合并。合并算法确保从列表中删除重复项,并确保合并后的监听器集根据
AnnotationAwareOrderComparator 的语义排序,如排序 TestExecutionListener 实现中所述。如果监听器实现了 Ordered 或被
@Order 注解,它可以影响与默认监听器合并的位置。否则,在合并时,本地声明的监听器将附加到默认监听器的列表中。
For example, if the MyCustomTestExecutionListener class in the previous example configures its order value (for
example, 500) to be less than the order of the ServletTestExecutionListener (which happens to be 1000), the
MyCustomTestExecutionListener can then be automatically merged with the list of defaults in front of the
ServletTestExecutionListener, and the previous example could be replaced with the following:
例如,如果前一个示例中的 MyCustomTestExecutionListener 类将其 order 值(例如, 500 )配置为小于
ServletTestExecutionListener 的顺序(恰好是 1000 ),那么 MyCustomTestExecutionListener 就可以自动与前一个
ServletTestExecutionListener 前的默认值列表合并,前一个示例可以替换为以下内容:
3.5.4. 应用事件
Since Spring Framework 5.3.3, the TestContext framework provides support for
recording application events
published in the ApplicationContext so that assertions can be performed against those events within tests. All events
published during the execution of a single test are made available via the ApplicationEvents API which allows you to
process the events as a java.util.Stream.
自 Spring Framework 5.3.3 以来,TestContext 框架提供了对记录在 ApplicationContext
中发布的应用程序事件的支撑,以便在测试中对这些事件进行断言。单个测试执行期间发布的所有事件都通过 ApplicationEvents API
提供,该 API 允许您将事件作为 java.util.Stream 进行处理。
To use ApplicationEvents in your tests, do the following.
要在测试中使用 ApplicationEvents ,请按照以下步骤操作。
Ensure that your test class is annotated or meta-annotated with
@RecordApplicationEvents.
确保您的测试类使用 @RecordApplicationEvents 进行注解或元注解。
Ensure that the ApplicationEventsTestExecutionListener is registered. Note, however, that
ApplicationEventsTestExecutionListener is registered by default and only needs to be manually registered if you have
custom configuration via @TestExecutionListeners that does not include the default listeners.
确保 ApplicationEventsTestExecutionListener 已注册。注意,然而, ApplicationEventsTestExecutionListener 默认已注册,只有在你通过
@TestExecutionListeners 进行自定义配置且该配置不包括默认监听器时才需要手动注册。
Annotate a field of type ApplicationEvents with @Autowired and use that instance of ApplicationEvents in your
test and lifecycle methods (such as @BeforeEach and @AfterEach methods in JUnit Jupiter).
注释类型为 ApplicationEvents 的字段为 @Autowired ,并在您的测试和生命周期方法(如 JUnit Jupiter 中的 @BeforeEach 和
@AfterEach 方法)中使用该 ApplicationEvents 实例。
ApplicationEvents in a test or lifecycle method as an alternative to an @Autowired field in
the test class.ApplicationEvents
的方法参数,作为在测试类中声明 @Autowired 字段的替代方案。The following test class uses the SpringExtension for JUnit Jupiter and AssertJ to
assert the types of application events published while invoking a method in a Spring-managed component:
以下测试类使用 SpringExtension 为 JUnit Jupiter 和 AssertJ 断言在调用 Spring 管理的组件中的方法时发布的应用程序事件的类型:
1
Annotate the test class with @RecordApplicationEvents.
为测试类添加 @RecordApplicationEvents 注解。
2
Inject the ApplicationEvents instance for the current test.
注入当前测试的 ApplicationEvents 实例。
3
Use the ApplicationEvents API to count how many OrderSubmitted events were published.
使用 ApplicationEvents API 来计算发布了多少个 OrderSubmitted 事件。
1
Annotate the test class with @RecordApplicationEvents.
2
Inject the ApplicationEvents instance for the current test.
3
Use the ApplicationEvents API to count how many OrderSubmitted events were published.
See the
ApplicationEvents javadoc
for further details regarding the ApplicationEvents API.
查看 ApplicationEvents javadoc 以获取有关 ApplicationEvents API 的更多详细信息。
3.5.5. 测试执行事件
The EventPublishingTestExecutionListener introduced in Spring Framework 5.2 offers an alternative approach to
implementing a custom TestExecutionListener. Components in the test’s ApplicationContext can listen to the following
events published by the EventPublishingTestExecutionListener, each of which corresponds to a method in the
TestExecutionListener API.
Spring Framework 5.2 中引入的 EventPublishingTestExecutionListener 提供了实现自定义 TestExecutionListener 的另一种方法。测试的
ApplicationContext 组件可以监听 EventPublishingTestExecutionListener 发布的以下事件,每个事件都对应于
TestExecutionListener API 中的一个方法。
BeforeTestClassEvent
PrepareTestInstanceEvent
BeforeTestMethodEvent
BeforeTestExecutionEvent
AfterTestExecutionEvent
AfterTestMethodEvent
AfterTestClassEvent
These events may be consumed for various reasons, such as resetting mock beans or tracing test execution. One advantage
of consuming test execution events rather than implementing a custom TestExecutionListener is that test execution
events may be consumed by any Spring bean registered in the test ApplicationContext, and such beans may benefit
directly from dependency injection and other features of the ApplicationContext. In contrast, a
TestExecutionListener is not a bean in the ApplicationContext.
这些事件可能因各种原因而被消费,例如重置模拟豆或跟踪测试执行。与实现自定义 TestExecutionListener
相比,消费测试执行事件的一个优点是,测试执行事件可以被测试 ApplicationContext 中注册的任何 Spring 豆消费,并且这些豆可以直接从
ApplicationContext 的依赖注入和其他功能中受益。相比之下, TestExecutionListener 不是 ApplicationContext 中的豆。
The EventPublishingTestExecutionListener is registered by default; however, it only publishes events if the
ApplicationContext has already been loaded. This prevents the ApplicationContext from being loaded unnecessarily
or too early.
默认情况下注册了 EventPublishingTestExecutionListener ;然而,只有当 ApplicationContext 已经被加载时,它才会发布事件。这防止了
ApplicationContext 不必要或过早地被加载。
Consequently, a BeforeTestClassEvent will not be published until after the ApplicationContext has been loaded by
another TestExecutionListener. For example, with the default set of TestExecutionListener implementations
registered, a BeforeTestClassEvent will not be published for the first test class that uses a particular test
ApplicationContext, but a BeforeTestClassEvent will be published for any subsequent test class in the same test
suite that uses the same test ApplicationContext since the context will already have been loaded when subsequent test
classes run (as long as the context has not been removed from the ContextCache via @DirtiesContext or the max-size
eviction policy).
因此,一个 BeforeTestClassEvent 将在另一个 ApplicationContext 被另一个 TestExecutionListener 加载后才发布。例如,在默认的
TestExecutionListener 实现集注册的情况下,对于第一个使用特定测试 ApplicationContext 的测试类,将不会发布一个
BeforeTestClassEvent ,但对于同一测试套件中任何后续使用相同测试 ApplicationContext 的测试类,将发布一个
BeforeTestClassEvent ,因为后续测试类运行时上下文已经加载(只要上下文没有被通过 @DirtiesContext 或最大大小驱逐策略从
ContextCache 中移除)。
If you wish to ensure that a BeforeTestClassEvent is always published for every test class, you need to register a
TestExecutionListener that loads the ApplicationContext in the beforeTestClass callback, and that
TestExecutionListener must be registered before the EventPublishingTestExecutionListener.
如果您希望确保每个测试类都始终发布一个 BeforeTestClassEvent ,您需要在 beforeTestClass 回调中注册一个加载
ApplicationContext 的 TestExecutionListener ,并且 TestExecutionListener 必须在
EventPublishingTestExecutionListener 之前注册。
Similarly, if @DirtiesContext is used to remove the ApplicationContext from the context cache after the last test
method in a given test class, the AfterTestClassEvent will not be published for that test class.
同样,如果在给定测试类的最后一个测试方法之后使用 @DirtiesContext 来从上下文缓存中移除 ApplicationContext ,则
AfterTestClassEvent 将不会为该测试类发布。
In order to listen to test execution events, a Spring bean may choose to implement the
org.springframework.context.ApplicationListener interface. Alternatively, listener methods can be annotated with
@EventListener and configured to listen to one of the particular event types listed above (
see Annotation-based Event Listeners).
Due to the popularity of this approach, Spring provides the following dedicated @EventListener annotations to simplify
registration of test execution event listeners. These annotations reside in the
org.springframework.test.context.event.annotation package.
为了监听测试执行事件,Spring Bean 可以选择实现 org.springframework.context.ApplicationListener 接口。或者,监听器方法可以用
@EventListener 注解,并配置为监听上述列出的特定事件类型之一(参见基于注解的事件监听器)。由于这种方法很受欢迎,Spring
提供了以下专门的 @EventListener 注解来简化测试执行事件监听器的注册。这些注解位于
org.springframework.test.context.event.annotation 包中。
@BeforeTestClass
@PrepareTestInstance
@BeforeTestMethod
@BeforeTestExecution
@AfterTestExecution
@AfterTestMethod
@AfterTestClass
By default, if a test execution event listener throws an exception while consuming an event, that exception will
propagate to the underlying testing framework in use (such as JUnit or TestNG). For example, if the consumption of a
BeforeTestMethodEvent results in an exception, the corresponding test method will fail as a result of the exception.
In contrast, if an asynchronous test execution event listener throws an exception, the exception will not propagate to
the underlying testing framework.
默认情况下,如果测试执行事件监听器在处理事件时抛出异常,该异常将传播到所使用的底层测试框架(如 JUnit 或 TestNG)。例如,如果消费
BeforeTestMethodEvent
导致异常,相应的测试方法将因异常而失败。相比之下,如果异步测试执行事件监听器抛出异常,该异常不会传播到底层测试框架。
For further details on asynchronous exception handling, consult the class-level javadoc for @EventListener.
关于异步异常处理的更多详细信息,请参阅类级别的 javadoc @EventListener 。
If you want a particular test execution event listener to process events asynchronously, you can use Spring’s regular
@Async support.
For further details, consult the class-level javadoc for @EventListener.
如果您想使特定的测试执行事件监听器异步处理事件,可以使用 Spring 的常规 @Async 支持。有关详细信息,请参阅 @EventListener
的类级别 javadoc。
3.5.6. 上下文管理
Each TestContext provides context management and caching support for the test instance for which it is responsible.
Test instances do not automatically receive access to the configured ApplicationContext. However, if a test class
implements the ApplicationContextAware interface, a reference to the ApplicationContext is supplied to the test
instance. Note that AbstractJUnit4SpringContextTests and AbstractTestNGSpringContextTests implement
ApplicationContextAware and, therefore, provide access to the ApplicationContext automatically.
每个 TestContext 为它负责的测试实例提供上下文管理和缓存支持。测试实例不会自动获得对配置的 ApplicationContext
的访问权限。然而,如果一个测试类实现了 ApplicationContextAware 接口,则会向测试实例提供一个 ApplicationContext 的引用。请注意,
AbstractJUnit4SpringContextTests 和 AbstractTestNGSpringContextTests 实现了 ApplicationContextAware ,因此可以自动提供对
ApplicationContext 的访问。
@Autowired ApplicationContext
As an alternative to implementing the ApplicationContextAware interface, you can inject the application context for
your test class through the @Autowired annotation on either a field or setter method, as the following example
shows:
作为实现 ApplicationContextAware 接口的替代方案,您可以通过在字段或 setter 方法上使用 @Autowired
注解来注入测试类的应用程序上下文,如下例所示:
1
Injecting the ApplicationContext. 注入 ApplicationContext 。
1
Injecting the ApplicationContext.
Similarly, if your test is configured to load a WebApplicationContext, you can inject the web application context into
your test, as follows:
同样,如果您的测试配置为加载一个 WebApplicationContext ,您可以将 Web 应用程序上下文注入到您的测试中,如下所示:
1
Configuring the WebApplicationContext. 配置 WebApplicationContext 。
2
Injecting the WebApplicationContext. 注入 WebApplicationContext 。
1
Configuring the WebApplicationContext.
2
Injecting the WebApplicationContext.
Dependency injection by using @Autowired is provided by the DependencyInjectionTestExecutionListener, which is
configured by default (see Dependency Injection of Test Fixtures).
通过使用 @Autowired 提供的依赖注入由 DependencyInjectionTestExecutionListener 提供,默认配置(参见测试固定件的依赖注入)。
Test classes that use the TestContext framework do not need to extend any particular class or implement a specific
interface to configure their application context. Instead, configuration is achieved by declaring the
@ContextConfiguration annotation at the class level. If your test class does not explicitly declare application
context resource locations or component classes, the configured ContextLoader determines how to load a context from a
default location or default configuration classes. In addition to context resource locations and component classes, an
application context can also be configured through application context initializers.
The following sections explain how to use Spring’s @ContextConfiguration annotation to configure a test
ApplicationContext by using XML configuration files, Groovy scripts, component classes (typically @Configuration
classes), or context initializers. Alternatively, you can implement and configure your own custom SmartContextLoader
for advanced use cases.
To load an ApplicationContext for your tests by using XML configuration files, annotate your test class with
@ContextConfiguration and configure the locations attribute with an array that contains the resource locations of
XML configuration metadata. A plain or relative path (for example, context.xml) is treated as a classpath resource
that is relative to the package in which the test class is defined. A path starting with a slash is treated as an
absolute classpath location (for example, /org/example/config.xml). A path that represents a resource URL (i.e., a
path prefixed with classpath:, file:, http:, etc.) is used as is.
1
Setting the locations attribute to a list of XML files.
1
Setting the locations attribute to a list of XML files.
@ContextConfiguration supports an alias for the locations attribute through the standard Java value attribute.
Thus, if you do not need to declare additional attributes in @ContextConfiguration, you can omit the declaration of
the locations attribute name and declare the resource locations by using the shorthand format demonstrated in the
following example:
1
Specifying XML files without using the location attribute.
1
Specifying XML files without using the location attribute.
If you omit both the locations and the value attributes from the @ContextConfiguration annotation, the TestContext
framework tries to detect a default XML resource location. Specifically, GenericXmlContextLoader and
GenericXmlWebContextLoader detect a default location based on the name of the test class. If your class is named
com.example.MyTest, GenericXmlContextLoader loads your application context from
"classpath:com/example/MyTest-context.xml". The following example shows how to do so:
如果您从 @ContextConfiguration 注解中省略了 locations 和 value 属性,TestContext 框架将尝试检测默认的 XML
资源位置。具体来说, GenericXmlContextLoader 和 GenericXmlWebContextLoader 根据测试类的名称检测默认位置。如果您的类名为
com.example.MyTest , GenericXmlContextLoader 将从 "classpath:com/example/MyTest-context.xml"
加载您的应用程序上下文。以下示例展示了如何这样做:
1
Loading configuration from the default location.
从默认位置加载配置。
1
Loading configuration from the default location.
上下文配置与 Groovy 脚本
To load an ApplicationContext for your tests by using Groovy scripts that use
the Groovy Bean Definition DSL,
you can annotate your test class with @ContextConfiguration and configure the locations or value attribute with an
array that contains the resource locations of Groovy scripts. Resource lookup semantics for Groovy scripts are the same
as those described for XML configuration files.
为了通过使用 Groovy 脚本加载测试用例,这些脚本使用 Groovy Bean 定义 DSL,您可以在测试类上使用 @ContextConfiguration
注解,并使用包含 Groovy 脚本资源位置的数组配置 locations 或 value 属性。Groovy 脚本的资源查找语义与描述 XML 配置文件的语义相同。
Enabling Groovy script support
启用 Groovy 脚本支持
Support for using Groovy scripts to load an ApplicationContext in the Spring TestContext Framework is enabled
automatically if Groovy is on the classpath.
支持在 Spring TestContext 框架中自动启用使用 Groovy 脚本加载 ApplicationContext 的功能,前提是 Groovy 已存在于类路径中。
The following example shows how to specify Groovy configuration files:
以下示例展示了如何指定 Groovy 配置文件:
1
Specifying the location of Groovy configuration files.
指定 Groovy 配置文件的位置。
1
Loading configuration from the default location.
If you omit both the locations and value attributes from the @ContextConfiguration annotation, the TestContext
framework tries to detect a default Groovy script. Specifically, GenericGroovyXmlContextLoader and
GenericGroovyXmlWebContextLoader detect a default location based on the name of the test class. If your class is named
com.example.MyTest, the Groovy context loader loads your application context from
"classpath:com/example/MyTestContext.groovy". The following example shows how to use the default:
如果您从 @ContextConfiguration 注解中省略了 locations 和 value 属性,TestContext 框架将尝试检测默认的 Groovy
脚本。具体来说, GenericGroovyXmlContextLoader 和 GenericGroovyXmlWebContextLoader 根据测试类的名称检测默认位置。如果您的类名为
com.example.MyTest ,Groovy 上下文加载器将从 "classpath:com/example/MyTestContext.groovy"
加载您的应用程序上下文。以下示例显示了如何使用默认设置:
1
Loading configuration from the default location.
从默认位置加载配置。
Declaring XML configuration and Groovy scripts simultaneously
同时声明 XML 配置和 Groovy 脚本
You can declare both XML configuration files and Groovy scripts simultaneously by using the locations or value
attribute of @ContextConfiguration. If the path to a configured resource location ends with .xml, it is loaded by
using an XmlBeanDefinitionReader. Otherwise, it is loaded by using a GroovyBeanDefinitionReader.
您可以通过使用 @ContextConfiguration 的 locations 或 value 属性同时声明 XML 配置文件和 Groovy 脚本。如果配置的资源位置路径以
.xml 结尾,则使用 XmlBeanDefinitionReader 加载。否则,使用 GroovyBeanDefinitionReader 加载。
The following listing shows how to combine both in an integration test:
以下列表展示了如何在集成测试中结合两者:
上下文配置与组件类
To load an ApplicationContext for your tests by using component classes (
see Java-based container configuration),
you can annotate your test class with @ContextConfiguration and configure the classes attribute with an array that
contains references to component classes. The following example shows how to do so:
为了通过使用组件类(参见基于 Java 的容器配置)加载一个 ApplicationContext 用于测试,您可以在测试类上使用
@ContextConfiguration 注解,并使用包含组件类引用的数组配置 classes 属性。以下示例展示了如何操作:
1
Specifying component classes.
指定组件类。
1
Specifying component classes.
Component Classes 组件类
The term “component class” can refer to any of the following:
组件类一词可以指以下任何一个:
A class annotated with @Configuration.
一个被 @Configuration 注解的类
A component (that is, a class annotated with @Component, @Service, @Repository, or other stereotype
annotations).
组件(即带有 @Component 、 @Service 、 @Repository 或其他类型注解的类)。
A JSR-330 compliant class that is annotated with javax.inject annotations.
一个符合 JSR-330 规范的类,带有 javax.inject 注解。
Any class that contains @Bean-methods.
任何包含 @Bean 方法的类。
Any other class that is intended to be registered as a Spring component (i.e., a Spring bean in the
ApplicationContext), potentially taking advantage of automatic autowiring of a single constructor without the use of
Spring annotations.
任何其他打算注册为 Spring 组件的类(即,在 ApplicationContext 中的 Spring Bean),可能利用单构造函数的自动装配功能,而不使用
Spring 注解。
See the javadoc of
@Configuration
and
@Bean
for further information regarding the configuration and semantics of component classes, paying special attention to the
discussion of @Bean Lite Mode.
查看 @Configuration 和 @Bean 的 javadoc 以获取有关组件类配置和语义的更多信息,特别关注对 @Bean 轻量模式的讨论。
If you omit the classes attribute from the @ContextConfiguration annotation, the TestContext framework tries to
detect the presence of default configuration classes. Specifically, AnnotationConfigContextLoader and
AnnotationConfigWebContextLoader detect all static nested classes of the test class that meet the requirements for
configuration class implementations, as specified in the
@Configuration
javadoc. Note that the name of the configuration class is arbitrary. In addition, a test class can contain more than one
static nested configuration class if desired. In the following example, the OrderServiceTest class declares a
static nested configuration class named Config that is automatically used to load the ApplicationContext for the
test class:
如果您省略了 @ContextConfiguration 注解中的 classes 属性,TestContext 框架将尝试检测默认配置类的存在。具体来说,
AnnotationConfigContextLoader 和 AnnotationConfigWebContextLoader 会检测测试类中所有满足配置类实现要求的 static
嵌套类,如 @Configuration javadoc 中指定。请注意,配置类的名称是任意的。此外,如果需要,测试类可以包含多个 static
嵌套配置类。在以下示例中, OrderServiceTest 类声明了一个名为 Config 的 static 嵌套配置类,该类将自动用于加载测试类的
ApplicationContext :
1
Loading configuration information from the nested Config class.
从嵌套的 Config 类中加载配置信息。
1
Loading configuration information from the nested Config class.
混合 XML、Groovy 脚本和组件类
It may sometimes be desirable to mix XML configuration files, Groovy scripts, and component classes (typically
@Configuration classes) to configure an ApplicationContext for your tests. For example, if you use XML configuration
in production, you may decide that you want to use @Configuration classes to configure specific Spring-managed
components for your tests, or vice versa.
有时可能希望混合 XML 配置文件、Groovy 脚本和组件类(通常是 @Configuration 类)来配置您的测试环境。例如,如果您在生产环境中使用
XML 配置,您可能决定想要使用 @Configuration 类来配置特定的 Spring 管理组件进行测试,反之亦然。
Furthermore, some third-party frameworks (such as Spring Boot) provide first-class support for loading an
ApplicationContext from different types of resources simultaneously (for example, XML configuration files, Groovy
scripts, and @Configuration classes). The Spring Framework, historically, has not supported this for standard
deployments. Consequently, most of the SmartContextLoader implementations that the Spring Framework delivers in the
spring-test module support only one resource type for each test context. However, this does not mean that you cannot
use both. One exception to the general rule is that the GenericGroovyXmlContextLoader and
GenericGroovyXmlWebContextLoader support both XML configuration files and Groovy scripts simultaneously. Furthermore,
third-party frameworks may choose to support the declaration of both locations and classes through
@ContextConfiguration, and, with the standard testing support in the TestContext framework, you have the following
options.
此外,一些第三方框架(如 Spring Boot)同时支持从不同类型的资源中加载 ApplicationContext ,提供了一级支持(例如,XML
配置文件、Groovy 脚本和 @Configuration 类)。历史上,Spring 框架不支持标准部署中的此功能。因此,Spring 框架在 spring-test
模块中提供的 SmartContextLoader 实现通常只支持每个测试上下文的一种资源类型。但这并不意味着你不能同时使用它们。一般规则的例外是
GenericGroovyXmlContextLoader 和 GenericGroovyXmlWebContextLoader 同时支持 XML 配置文件和 Groovy 脚本。此外,第三方框架可以选择通过
@ContextConfiguration 支持 locations 和 classes 的声明,并且,在 TestContext 框架的标准测试支持中,你有以下选项。
If you want to use resource locations (for example, XML or Groovy) and @Configuration classes to configure your tests,
you must pick one as the entry point, and that one must include or import the other. For example, in XML or Groovy
scripts, you can include @Configuration classes by using component scanning or defining them as normal Spring beans,
whereas, in a @Configuration class, you can use @ImportResource to import XML configuration files or Groovy scripts.
Note that this behavior is semantically equivalent to how you configure your application in production: In production
configuration, you define either a set of XML or Groovy resource locations or a set of @Configuration classes from
which your production ApplicationContext is loaded, but you still have the freedom to include or import the other type
of configuration.
如果您想使用资源位置(例如,XML 或 Groovy)和 @Configuration 类来配置测试,您必须选择其中一个作为入口点,并且该入口点必须包含或导入另一个。例如,在
XML 或 Groovy 脚本中,您可以通过组件扫描或将它们定义为正常的 Spring bean 来包含 @Configuration 类,而在 @Configuration
类中,您可以使用 @ImportResource 导入 XML 配置文件或 Groovy 脚本。请注意,此行为在语义上与您在生产中配置应用程序的方式相同:在生产配置中,您定义一组
XML 或 Groovy 资源位置或一组 @Configuration 类,您的生产 ApplicationContext 从中加载,但您仍然有包含或导入其他类型配置的自由。
上下文配置与上下文初始化器
To configure an ApplicationContext for your tests by using context initializers, annotate your test class with
@ContextConfiguration and configure the initializers attribute with an array that contains references to classes
that implement ApplicationContextInitializer. The declared context initializers are then used to initialize the
ConfigurableApplicationContext that is loaded for your tests. Note that the concrete ConfigurableApplicationContext
type supported by each declared initializer must be compatible with the type of ApplicationContext created by the
SmartContextLoader in use (typically a GenericApplicationContext). Furthermore, the order in which the initializers
are invoked depends on whether they implement Spring’s Ordered interface or are annotated with Spring’s @Order
annotation or the standard @Priority annotation. The following example shows how to use initializers:
为了通过使用上下文初始化器配置一个 ApplicationContext 以供测试使用,请使用 @ContextConfiguration 注解您的测试类,并将
initializers 属性配置为一个包含实现 ApplicationContextInitializer 的类引用的数组。然后,声明的上下文初始化器用于初始化为您的测试加载的
ConfigurableApplicationContext 。请注意,每个声明的初始化器支持的 ConfigurableApplicationContext 具体类型必须与由
SmartContextLoader 创建的 ApplicationContext 的类型兼容(通常是一个 GenericApplicationContext
)。此外,初始化器的调用顺序取决于它们是否实现了 Spring 的 Ordered 接口或被 Spring 的 @Order 注解或标准的 @Priority
注解注解。以下示例显示了如何使用初始化器:
1
Specifying configuration by using a configuration class and an initializer.
通过配置类和初始化器指定配置
1
Specifying configuration by using a configuration class and an initializer.
You can also omit the declaration of XML configuration files, Groovy scripts, or component classes in
@ContextConfiguration entirely and instead declare only ApplicationContextInitializer classes, which are then
responsible for registering beans in the context — for example, by programmatically loading bean definitions from XML
files or configuration classes. The following example shows how to do so:
您也可以在 @ContextConfiguration 中完全省略 XML 配置文件、Groovy 脚本或组件类的声明,而只声明
ApplicationContextInitializer 类,这些类随后负责在上下文中注册 bean——例如,通过从 XML 文件或配置类中程序化加载 bean
定义。以下示例展示了如何操作:
1
Specifying configuration by using only an initializer.
仅使用初始化器指定配置。
1
Specifying configuration by using only an initializer.
上下文配置继承
@ContextConfiguration supports boolean inheritLocations and inheritInitializers attributes that denote whether
resource locations or component classes and context initializers declared by superclasses should be inherited. The
default value for both flags is true. This means that a test class inherits the resource locations or component
classes as well as the context initializers declared by any superclasses.
@ContextConfiguration 支持布尔 inheritLocations 和 inheritInitializers 属性,表示是否继承由超类声明的资源位置或组件类以及上下文初始化器。这两个标志的默认值是
true 。这意味着测试类继承了任何超类声明的资源位置、组件类以及上下文初始化器。
Specifically, the resource locations or component classes for a test class are appended to the list of resource
locations or annotated classes declared by superclasses.
具体来说,测试类的资源位置或组件类被附加到由超类声明的资源位置或注解类的列表中。
Similarly, the initializers for a given test class are added to the set of initializers defined by test superclasses.
Thus, subclasses have the option of extending the resource locations, component classes, or context initializers.
同样,给定测试类的初始化器被添加到由测试超类定义的初始化器集合中。因此,子类可以选择扩展资源位置、组件类或上下文初始化器。
If the inheritLocations or inheritInitializers attribute in @ContextConfiguration is set to false, the resource
locations or component classes and the context initializers, respectively, for the test class shadow and effectively
replace the configuration defined by superclasses.
如果 @ContextConfiguration 中的 inheritLocations 或 inheritInitializers 属性设置为 false
,则测试类阴影的资源位置或组件类以及上下文初始化器将分别有效地替换由超类定义的配置。
As of Spring Framework 5.3, test configuration may also be inherited from enclosing classes. See
@Nested test class configuration for details.
截至 Spring Framework 5.3,测试配置也可以从封装类继承。有关详细信息,请参阅 @Nested 测试类配置。
In the next example, which uses XML resource locations, the ApplicationContext for ExtendedTest is loaded from
base-config.xml and extended-config.xml, in that order. Beans defined in extended-config.xml can, therefore,
override (that is, replace) those defined in base-config.xml. The following example shows how one class can extend
another and use both its own configuration file and the superclass’s configuration file:
在下一个示例中,使用 XML 资源位置,按照顺序从 base-config.xml 和 extended-config.xml 加载 ApplicationContext 的
ExtendedTest 。因此,在 extended-config.xml 中定义的豆子可以覆盖(即替换)在 base-config.xml
中定义的豆子。以下示例展示了如何一个类可以扩展另一个类,并使用它自己的配置文件和超类的配置文件:
1
Configuration file defined in the superclass.
配置文件在超类中定义。
2
Configuration file defined in the subclass.
配置文件在子类中定义。
1
Configuration file defined in the superclass.
2
Configuration file defined in the subclass.
Similarly, in the next example, which uses component classes, the ApplicationContext for ExtendedTest is loaded from
the BaseConfig and ExtendedConfig classes, in that order. Beans defined in ExtendedConfig can, therefore,
override (that is, replace) those defined in BaseConfig. The following example shows how one class can extend another
and use both its own configuration class and the superclass’s configuration class:
同样,在下一个示例中,使用组件类的情况下, ApplicationContext 对于 ExtendedTest 是按照顺序从 BaseConfig 和
ExtendedConfig 类中加载的。因此,在 ExtendedConfig 中定义的 Bean 可以覆盖(即替换)在 BaseConfig 中定义的
Bean。以下示例展示了如何一个类可以扩展另一个类,并使用它自己的配置类和超类配置类:
1
Configuration class defined in the superclass.
配置类在超类中定义。
2
Configuration class defined in the subclass.
子类中定义的配置类。
1
Configuration class defined in the superclass.
2
Configuration class defined in the subclass.
In the next example, which uses context initializers, the ApplicationContext for ExtendedTest is initialized by
using BaseInitializer and ExtendedInitializer. Note, however, that the order in which the initializers are invoked
depends on whether they implement Spring’s Ordered interface or are annotated with Spring’s @Order annotation or the
standard @Priority annotation. The following example shows how one class can extend another and use both its own
initializer and the superclass’s initializer:
在下例中,使用上下文初始化器时, ApplicationContext 对 ExtendedTest 的初始化是通过使用 BaseInitializer 和
ExtendedInitializer 实现的。请注意,初始化器的调用顺序取决于它们是否实现了 Spring 的 Ordered 接口或被 Spring 的
@Order 注解或标准 @Priority 注解标注。以下示例展示了如何一个类可以扩展另一个类并使用它自己的初始化器和超类初始化器:
1
Initializer defined in the superclass.
父类中定义的初始化器。
2
Initializer defined in the subclass.
子类中定义的初始化器。
1
Initializer defined in the superclass.
2
Initializer defined in the subclass.
上下文配置与环境配置文件
The Spring Framework has first-class support for the notion of environments and profiles (AKA "bean definition
profiles"), and integration tests can be configured to activate particular bean definition profiles for various testing
scenarios.
Spring 框架对环境和配置(又称“bean 定义配置”)的概念提供了一等支持,并且集成测试可以配置以激活特定 bean
定义配置,以适应各种测试场景。
This is achieved by annotating a test class with the @ActiveProfiles annotation and supplying a list of profiles that
should be activated when loading the ApplicationContext for the test.
这是通过使用 @ActiveProfiles 注解注释测试类,并供应一个在加载测试的 ApplicationContext 时应激活的配置文件列表来实现的。
You can use @ActiveProfiles with any implementation of the SmartContextLoader SPI, but @ActiveProfiles is not
supported with implementations of the older ContextLoader SPI.
您可以使用 @ActiveProfiles 与任何 SmartContextLoader SPI 的实现一起使用,但 @ActiveProfiles 不支持与较旧的
ContextLoader SPI 的实现一起使用。
Consider two examples with XML configuration and @Configuration classes:
考虑两个具有 XML 配置和 @Configuration 类的示例:
When TransferServiceTest is run, its ApplicationContext is loaded from the app-config.xml configuration file in
the root of the classpath. If you inspect app-config.xml, you can see that the accountRepository bean has a
dependency on a dataSource bean. However, dataSource is not defined as a top-level bean. Instead, dataSource is
defined three times: in the production profile, in the dev profile, and in the default profile.
当运行 TransferServiceTest 时,其 ApplicationContext 从类路径根目录下的 app-config.xml 配置文件中加载。如果您检查
app-config.xml ,您可以看到 accountRepository 容器依赖于一个 dataSource 容器。然而, dataSource 没有定义为顶级容器。相反,
dataSource 定义了三次:在 production 配置文件中,在 dev 配置文件中,以及在 default 配置文件中。
By annotating TransferServiceTest with @ActiveProfiles("dev"), we instruct the Spring TestContext Framework to load
the ApplicationContext with the active profiles set to {"dev"}. As a result, an embedded database is created and
populated with test data, and the accountRepository bean is wired with a reference to the development DataSource.
That is likely what we want in an integration test.
通过注释 TransferServiceTest 为 @ActiveProfiles("dev") ,我们指示 Spring TestContext 框架加载 ApplicationContext
,并将活动配置设置为 {"dev"} 。因此,将创建一个嵌入数据库并填充测试数据,并将 accountRepository bean 与开发 DataSource
的引用连接起来。这可能是我们想要的集成测试结果。
It is sometimes useful to assign beans to a default profile. Beans within the default profile are included only when
no other profile is specifically activated. You can use this to define “fallback” beans to be used in the application’s
default state. For example, you may explicitly provide a data source for dev and production profiles, but define an
in-memory data source as a default when neither of these is active.
有时将豆子分配给一个 default 配置文件是有用的。默认配置文件中的豆子只有在没有其他特定配置文件激活时才会包含。您可以使用此功能定义在应用程序默认状态下使用的“回退”豆子。例如,您可以为
dev 和 production 配置文件明确提供数据源,但在这些配置文件都不活跃时,将内存数据源定义为默认值。
The following code listings demonstrate how to implement the same configuration and integration test with
@Configuration classes instead of XML:
以下代码示例展示了如何使用 @Configuration 类而不是 XML 来实现相同的配置和集成测试:
In this variation, we have split the XML configuration into four independent @Configuration classes:
在这个变体中,我们将 XML 配置拆分成了四个独立的 @Configuration 类:
TransferServiceConfig: Acquires a dataSource through dependency injection by using @Autowired.
通过依赖注入使用 @Autowired 获取一个 dataSource 。
StandaloneDataConfig: Defines a dataSource for an embedded database suitable for developer tests.
StandaloneDataConfig :为适合开发者测试的嵌入式数据库定义了一个 dataSource 。
JndiDataConfig: Defines a dataSource that is retrieved from JNDI in a production environment.
JndiDataConfig :定义一个在生产环境中从 JNDI 检索的 dataSource 。
DefaultDataConfig: Defines a dataSource for a default embedded database, in case no profile is active.
DefaultDataConfig :定义一个默认嵌入式数据库的 dataSource ,以防没有活动配置文件。
As with the XML-based configuration example, we still annotate TransferServiceTest with @ActiveProfiles("dev"), but
this time we specify all four configuration classes by using the @ContextConfiguration annotation. The body of the
test class itself remains completely unchanged.
与基于 XML 的配置示例一样,我们仍然使用 TransferServiceTest 注解 @ActiveProfiles("dev") ,但这次我们通过
@ContextConfiguration 注解指定了所有四个配置类。测试类的主体本身完全未变。
It is often the case that a single set of profiles is used across multiple test classes within a given project. Thus, to
avoid duplicate declarations of the @ActiveProfiles annotation, you can declare @ActiveProfiles once on a base
class, and subclasses automatically inherit the @ActiveProfiles configuration from the base class. In the following
example, the declaration of @ActiveProfiles (as well as other annotations) has been moved to an abstract superclass,
AbstractIntegrationTest:
通常情况下,在同一个项目内,多个测试类会使用同一组配置文件。因此,为了避免重复声明 @ActiveProfiles 注解,您可以在基类上一次性声明
@ActiveProfiles ,子类会自动从基类继承 @ActiveProfiles 配置。在下面的示例中, @ActiveProfiles (以及其他注解)的声明已被移动到一个抽象超类
AbstractIntegrationTest :
As of Spring Framework 5.3, test configuration may also be inherited from enclosing classes. See
@Nested test class configuration for details.
截至 Spring Framework 5.3,测试配置也可以从封装类继承。有关详细信息,请参阅 @Nested 测试类配置。
@ActiveProfiles also supports an inheritProfiles attribute that can be used to disable the inheritance of active
profiles, as the following example shows:
@ActiveProfiles 也支持一个 inheritProfiles 属性,可以用来禁用活动配置文件的继承,如下例所示:
Furthermore, it is sometimes necessary to resolve active profiles for tests programmatically instead of declaratively —
for example, based on:
此外,有时需要根据以下内容以编程方式而不是声明方式解决测试的活跃配置文件——例如,基于:
The current operating system.
当前操作系统。
Whether tests are being run on a continuous integration build server.
是否在持续集成构建服务器上运行测试。
The presence of certain environment variables.
某些环境变量的存在。
The presence of custom class-level annotations.
存在自定义类级别注解。
Other concerns. 其他关注点。
To resolve active bean definition profiles programmatically, you can implement a custom ActiveProfilesResolver and
register it by using the resolver attribute of @ActiveProfiles. For further information, see the
corresponding javadoc.
The following example demonstrates how to implement and register a custom OperatingSystemActiveProfilesResolver:
为了程序化地解决活动 Bean 定义配置,您可以实现一个自定义的 ActiveProfilesResolver 并通过使用 @ActiveProfiles 的
resolver 属性来注册它。有关更多信息,请参阅相应的 javadoc。以下示例演示了如何实现和注册一个自定义的
OperatingSystemActiveProfilesResolver :
上下文配置与测试属性源
The Spring Framework has first-class support for the notion of an environment with a hierarchy of property sources, and
you can configure integration tests with test-specific property sources. In contrast to the @PropertySource annotation
used on @Configuration classes, you can declare the @TestPropertySource annotation on a test class to declare
resource locations for test properties files or inlined properties. These test property sources are added to the set of
PropertySources in the Environment for the ApplicationContext loaded for the annotated integration test.
Spring 框架对具有属性源层次结构的环境概念提供了一级支持,您可以使用特定于测试的属性源配置集成测试。与用于 @Configuration
类的 @PropertySource 注解相比,您可以在测试类上声明 @TestPropertySource 注解,以声明测试属性文件或内联属性的资源位置。这些测试属性源被添加到为
ApplicationContext 加载的注解集成测试的 Environment 中的 PropertySources 集合中。
You can use @TestPropertySource with any implementation of the SmartContextLoader SPI, but @TestPropertySource is
not supported with implementations of the older ContextLoader SPI.
您可以使用 @TestPropertySource 与任何 SmartContextLoader SPI 的实现一起使用,但 @TestPropertySource 不支持与较旧的
ContextLoader SPI 的实现一起使用。
Implementations of SmartContextLoader gain access to merged test property source values through the
getPropertySourceLocations() and getPropertySourceProperties() methods in MergedContextConfiguration.
实现 SmartContextLoader 可以通过 MergedContextConfiguration 中的 getPropertySourceLocations() 和
getPropertySourceProperties() 方法访问合并后的测试属性源值。
声明测试属性源
You can configure test properties files by using the locations or value attribute of @TestPropertySource.
您可以通过使用 @TestPropertySource 的 locations 或 value 属性来配置测试属性文件。
Both traditional and XML-based properties file formats are supported — for example,
"classpath:/com/example/test.properties" or "file:///path/to/file.xml".
传统和基于 XML 的属性文件格式都受支持——例如, "classpath:/com/example/test.properties" 或
"file:///path/to/file.xml" 。
Each path is interpreted as a Spring Resource. A plain path (for example, "test.properties") is treated as a
classpath resource that is relative to the package in which the test class is defined. A path starting with a slash is
treated as an absolute classpath resource (for example: "/org/example/test.xml"). A path that references a URL (for
example, a path prefixed with classpath:, file:, or http:) is loaded by using the specified resource protocol.
Resource location wildcards (such as ***/**.properties) are not permitted: Each location must evaluate to exactly one
.properties or .xml resource.
每条路径都被解释为 Spring Resource 。一个普通路径(例如, "test.properties" )被视为相对于定义测试类的包的类路径资源。以斜杠开头的路径被视为绝对类路径资源(例如:
"/org/example/test.xml" )。引用 URL 的路径(例如,以 classpath: 、 file: 或 http: 为前缀的路径)将通过指定的资源协议加载。不允许使用资源位置通配符(如
***/**.properties ):每个位置必须精确评估为一条 .properties 或 .xml 资源。
The following example uses a test properties file:
以下示例使用一个测试属性文件:
1
Specifying a properties file with an absolute path.
指定一个带有绝对路径的属性文件。
1
Specifying a properties file with an absolute path.
You can configure inlined properties in the form of key-value pairs by using the properties attribute of
@TestPropertySource, as shown in the next example. All key-value pairs are added to the enclosing Environment as a
single test PropertySource with the highest precedence.
您可以通过使用 @TestPropertySource 的 properties 属性以键值对的形式配置内联属性,如下例所示。所有键值对都作为一个具有最高优先级的单个测试
PropertySource 添加到包含的 Environment 中。
The supported syntax for key-value pairs is the same as the syntax defined for entries in a Java properties file:
支持键值对的语法与定义在 Java 属性文件中的条目语法相同:
key=value
key:value
key value
The following example sets two inlined properties:
以下示例设置了两个内联属性:
1
Setting two properties by using two variations of the key-value syntax.
通过两种键值语法变体设置两个属性。
1
Setting two properties by using two variations of the key-value syntax.
As of Spring Framework 5.2, @TestPropertySource can be used as repeatable annotation. That means that you can have
multiple declarations of @TestPropertySource on a single test class, with the locations and properties from later
@TestPropertySource annotations overriding those from previous @TestPropertySource annotations.
截至 Spring Framework 5.2, @TestPropertySource 可以用作可重复注解。这意味着您可以在单个测试类中多次声明
@TestPropertySource ,后续 @TestPropertySource 注解中的 locations 和 properties 将覆盖先前 @TestPropertySource
注解中的那些。
In addition, you may declare multiple composed annotations on a test class that are each meta-annotated with
@TestPropertySource, and all of those @TestPropertySource declarations will contribute to your test property
sources.
此外,您可以在测试类上声明多个组合注解,每个注解都使用 @TestPropertySource 进行元注解,并且所有这些 @TestPropertySource
声明都将贡献到您的测试属性源。
Directly present @TestPropertySource annotations always take precedence over meta-present @TestPropertySource
annotations. In other words, locations and properties from a directly present @TestPropertySource annotation will
override the locations and properties from a @TestPropertySource annotation used as a meta-annotation.
直接呈现的 @TestPropertySource 注解始终优先于元呈现的 @TestPropertySource 注解。换句话说,直接呈现的
@TestPropertySource 注解中的 locations 和 properties 将覆盖用作元注解的 @TestPropertySource 注解中的 locations
和 properties 。
默认属性文件检测
If @TestPropertySource is declared as an empty annotation (that is, without explicit values for the locations or
properties attributes), an attempt is made to detect a default properties file relative to the class that declared the
annotation. For example, if the annotated test class is com.example.MyTest, the corresponding default properties file
is classpath:com/example/MyTest.properties. If the default cannot be detected, an IllegalStateException is thrown.
如果 @TestPropertySource 被声明为一个空注解(即没有为 locations 或 properties
属性指定显式值),则会尝试检测相对于声明注解的类的一个默认属性文件。例如,如果被注解的测试类是 com.example.MyTest
,则相应的默认属性文件是 classpath:com/example/MyTest.properties 。如果无法检测到默认值,则会抛出 IllegalStateException
异常。
Test properties have higher precedence than those defined in the operating system’s environment, Java system properties,
or property sources added by the application declaratively by using @PropertySource or programmatically. Thus, test
properties can be used to selectively override properties loaded from system and application property sources.
Furthermore, inlined properties have higher precedence than properties loaded from resource locations.
测试属性比操作系统环境、Java 系统属性或通过 @PropertySource
或程序方式声明添加的应用属性源中定义的属性具有更高的优先级。因此,可以使用测试属性有选择地覆盖从系统和应用程序属性源加载的属性。此外,内联属性比从资源位置加载的属性具有更高的优先级。
Note, however, that properties registered via
@DynamicPropertySource have higher precedence than those loaded
via @TestPropertySource.
注意,然而,通过 @DynamicPropertySource 注册的属性比通过 @TestPropertySource 加载的属性具有更高的优先级。
In the next example, the timezone and port properties and any properties defined in "/test.properties" override
any properties of the same name that are defined in system and application property sources. Furthermore, if the
"/test.properties" file defines entries for the timezone and port properties those are overridden by the inlined
properties declared by using the properties attribute. The following example shows how to specify properties both in a
file and inline:
在下例中, timezone 和 port 属性以及定义在 "/test.properties" 中的任何属性会覆盖在系统和应用程序属性源中定义的同名属性。此外,如果
"/test.properties" 文件定义了 timezone 和 port 属性的条目,这些条目会被使用 properties
属性声明的内联属性覆盖。以下示例展示了如何在文件和内联中指定属性:
继承和覆盖测试属性源
@TestPropertySource supports boolean inheritLocations and inheritProperties attributes that denote whether
resource locations for properties files and inlined properties declared by superclasses should be inherited. The default
value for both flags is true. This means that a test class inherits the locations and inlined properties declared by
any superclasses. Specifically, the locations and inlined properties for a test class are appended to the locations and
inlined properties declared by superclasses.
@TestPropertySource 支持布尔 inheritLocations 和 inheritProperties 属性,表示是否应该继承属性文件和由超类声明的内联属性的资源位置。这两个标志的默认值是
true
。这意味着测试类会继承任何超类声明的位置和内联属性。具体来说,测试类的位置和内联属性会被追加到超类声明的位置和内联属性中。
Thus, subclasses have the option of extending the locations and inlined properties. Note that properties that appear
later shadow (that is, override) properties of the same name that appear earlier.
因此,子类可以选择扩展位置和内联属性。请注意,后来出现的属性会覆盖(即覆盖)之前出现的同名属性。
In addition, the aforementioned precedence rules apply for inherited test property sources as well.
此外,上述优先级规则也适用于继承的测试属性源。
If the inheritLocations or inheritProperties attribute in @TestPropertySource is set to false, the locations or
inlined properties, respectively, for the test class shadow and effectively replace the configuration defined by
superclasses.
如果 @TestPropertySource 中的 inheritLocations 或 inheritProperties 属性设置为 false
,则分别替换测试类阴影的位置或内联属性,从而有效地替代超类定义的配置。
As of Spring Framework 5.3, test configuration may also be inherited from enclosing classes. See
@Nested test class configuration for details.
截至 Spring Framework 5.3,测试配置也可以从封装类继承。有关详细信息,请参阅 @Nested 测试类配置。
In the next example, the ApplicationContext for BaseTest is loaded by using only the base.properties file as a
test property source. In contrast, the ApplicationContext for ExtendedTest is loaded by using the base.properties
and extended.properties files as test property source locations. The following example shows how to define properties
in both a subclass and its superclass by using properties files:
在下例中,仅使用 base.properties 文件作为测试属性源,加载了 BaseTest 的 ApplicationContext 。相比之下,使用
base.properties 和 extended.properties 文件作为测试属性源位置,加载了 ExtendedTest 的 ApplicationContext
。以下示例展示了如何通过 properties 文件在子类及其超类中定义属性:
In the next example, the ApplicationContext for BaseTest is loaded by using only the inlined key1 property. In
contrast, the ApplicationContext for ExtendedTest is loaded by using the inlined key1 and key2 properties. The
following example shows how to define properties in both a subclass and its superclass by using inline properties:
在下例中,通过仅使用内联的 key1 属性来加载 BaseTest 的 ApplicationContext 。相比之下,通过使用内联的 key1 和 key2
属性来加载 ExtendedTest 的 ApplicationContext 。以下示例展示了如何通过使用内联属性在子类及其超类中定义属性:
上下文配置与动态属性源
As of Spring Framework 5.2.5, the TestContext framework provides support for dynamic properties via the
@DynamicPropertySource annotation. This annotation can be used in integration tests that need to add properties with
dynamic values to the set of PropertySources in the Environment for the ApplicationContext loaded for the
integration test.
截至 Spring Framework 5.2.5 版本,TestContext 框架通过 @DynamicPropertySource 注解提供了对动态属性的支撑。此注解可用于需要向
Environment 中的 PropertySources 集合添加具有动态值的属性的集成测试中,用于为集成测试加载的 ApplicationContext 。
The @DynamicPropertySource annotation and its supporting infrastructure were originally designed to allow properties
from Testcontainers based tests to be exposed easily to Spring integration tests.
However, this feature may also be used with any form of external resource whose lifecycle is maintained outside the
test’s ApplicationContext.
@DynamicPropertySource 注解及其支持的基础设施最初设计用于允许从基于 Testcontainers 的测试中轻松暴露属性到 Spring
集成测试。然而,此功能也可以与任何形式的外部资源一起使用,其生命周期由测试的 ApplicationContext 维护。
In contrast to the @TestPropertySource annotation that is applied at
the class level, @DynamicPropertySource must be applied to a static method that accepts a single
DynamicPropertyRegistry argument which is used to add name-value pairs to the Environment. Values are dynamic and
provided via a Supplier which is only invoked when the property is resolved. Typically, method references are used to
supply values, as can be seen in the following example which uses the Testcontainers project to manage a Redis container
outside of the Spring ApplicationContext. The IP address and port of the managed Redis container are made available to
components within the test’s ApplicationContext via the redis.host and redis.port properties. These properties can
be accessed via Spring’s Environment abstraction or injected directly into Spring-managed components – for example,
via @Value("${redis.host}") and @Value("${redis.port}"), respectively.
与在类级别应用的第 0#注释不同,第 1#必须应用于一个接受单个第 3#参数的第 2#方法,该参数用于将键值对添加到第 4#。值是动态的,通过一个第
5#提供,该第 5#仅在属性解析时调用。通常,使用方法引用来提供值,如下例所示,该例使用 Testcontainers 项目来管理 Spring 第 6#之外的
Redis 容器。管理的 Redis 容器的 IP 地址和端口通过第 8#和第 9#属性提供给测试的组件。这些属性可以通过 Spring 的第
10#抽象访问,或者直接注入到 Spring 管理的组件中——例如,分别通过第 11#和第 12#。
If you use @DynamicPropertySource in a base class and discover that tests in subclasses fail because the dynamic
properties change between subclasses, you may need to annotate your base class with
@DirtiesContext to ensure that each subclass gets its own
ApplicationContext with the correct dynamic properties.
如果您在基类中使用 @DynamicPropertySource ,并发现子类中的测试失败,因为动态属性在子类之间发生变化,您可能需要使用
@DirtiesContext 注释您的基类,以确保每个子类都获得自己的 ApplicationContext 并具有正确的动态属性。
Dynamic properties have higher precedence than those loaded from @TestPropertySource, the operating system’s
environment, Java system properties, or property sources added by the application declaratively by using
@PropertySource or programmatically. Thus, dynamic properties can be used to selectively override properties loaded
via @TestPropertySource, system property sources, and application property sources.
动态属性比从 @TestPropertySource 加载的属性具有更高的优先级,包括操作系统的环境、Java 系统属性或通过 @PropertySource
声明性添加或通过程序添加的应用程序属性源。因此,可以使用动态属性选择性地覆盖通过 @TestPropertySource 、系统属性源和应用属性源加载的属性。
WebApplicationContext 加载WebApplicationContextTo instruct the TestContext framework to load a WebApplicationContext instead of a standard ApplicationContext, you
can annotate the respective test class with @WebAppConfiguration.
要指示 TestContext 框架加载一个 WebApplicationContext 而不是标准 ApplicationContext ,您可以通过
@WebAppConfiguration 注解相应的测试类来实现。
The presence of @WebAppConfiguration on your test class instructs the TestContext framework (TCF) that a
WebApplicationContext (WAC) should be loaded for your integration tests. In the background, the TCF makes sure that a
MockServletContext is created and supplied to your test’s WAC. By default, the base resource path for your
MockServletContext is set to src/main/webapp. This is interpreted as a path relative to the root of your JVM (
normally the path to your project). If you are familiar with the directory structure of a web application in a Maven
project, you know that src/main/webapp is the default location for the root of your WAR. If you need to override this
default, you can provide an alternate path to the @WebAppConfiguration annotation (for example,
@WebAppConfiguration("src/test/webapp")). If you wish to reference a base resource path from the classpath instead of
the file system, you can use Spring’s classpath: prefix.
您的测试类中存在 @WebAppConfiguration 指示 TestContext 框架(TCF)为您的集成测试加载一个 WebApplicationContext
(WAC)。在后台,TCF 确保创建并供应一个 MockServletContext 给您的测试的 WAC。默认情况下,您的 MockServletContext
的基础资源路径设置为 src/main/webapp 。这被解释为相对于您的 JVM 根目录的路径(通常是项目路径)。如果您熟悉 Maven 项目中
Web 应用程序的目录结构,您知道 src/main/webapp 是 WAR 根目录的默认位置。如果您需要覆盖此默认值,可以为
@WebAppConfiguration 注解提供一个替代路径(例如, @WebAppConfiguration("src/test/webapp")
)。如果您希望从类路径而不是文件系统引用基础资源路径,可以使用 Spring 的 classpath: 前缀。
Note that Spring’s testing support for WebApplicationContext implementations is on par with its support for standard
ApplicationContext implementations. When testing with a WebApplicationContext, you are free to declare XML
configuration files, Groovy scripts, or @Configuration classes by using @ContextConfiguration. You are also free to
use any other test annotations, such as @ActiveProfiles, @TestExecutionListeners, @Sql, @Rollback, and others.
请注意,Spring 对 WebApplicationContext 实现的测试支持与对标准 ApplicationContext 实现的测试支持相当。当使用
WebApplicationContext 进行测试时,您可以使用 @ContextConfiguration 自由声明 XML 配置文件、Groovy 脚本或
@Configuration 类。您还可以自由使用任何其他测试注解,例如 @ActiveProfiles 、 @TestExecutionListeners 、 @Sql 、
@Rollback 以及其他。
The remaining examples in this section show some of the various configuration options for loading a
WebApplicationContext. The following example shows the TestContext framework’s support for convention over
configuration:
本节剩余的示例展示了加载 WebApplicationContext 的一些各种配置选项。以下示例展示了 TestContext 框架对约定优于配置的支持:
If you annotate a test class with @WebAppConfiguration without specifying a resource base path, the resource path
effectively defaults to file:src/main/webapp. Similarly, if you declare @ContextConfiguration without specifying
resource locations, component classes, or context initializers, Spring tries to detect the presence of your
configuration by using conventions (that is, WacTests-context.xml in the same package as the WacTests class or
static nested @Configuration classes).
如果您在测试类上使用 @WebAppConfiguration 注解而没有指定资源基本路径,则资源路径实际上默认为 file:src/main/webapp
。同样,如果您声明 @ContextConfiguration 而没有指定资源 locations 、组件 classes 或上下文 initializers ,Spring
会尝试通过约定(即在 WacTests 类或静态嵌套 @Configuration 类同一包中的 WacTests-context.xml )来检测您的配置是否存在。
The following example shows how to explicitly declare a resource base path with @WebAppConfiguration and an XML
resource location with @ContextConfiguration:
以下示例展示了如何使用 @WebAppConfiguration 显式声明资源基本路径,以及使用 @ContextConfiguration 指定 XML 资源位置:
The important thing to note here is the different semantics for paths with these two annotations. By default,
@WebAppConfiguration resource paths are file system based, whereas @ContextConfiguration resource locations are
classpath based.
需要注意的是这里这两种注解对路径的不同语义。默认情况下, @WebAppConfiguration 资源路径基于文件系统,而
@ContextConfiguration 资源位置基于类路径。
The following example shows that we can override the default resource semantics for both annotations by specifying a
Spring resource prefix:
以下示例显示,我们可以通过指定 Spring 资源前缀来覆盖默认的资源语义,以对注解进行操作:
Contrast the comments in this example with the previous example.
将本例中的注释与上一个例子进行对比。
Working with Web Mocks
与 Web 模拟器协作
To provide comprehensive web testing support, the TestContext framework has a ServletTestExecutionListener that is
enabled by default. When testing against a WebApplicationContext, this
TestExecutionListener sets up default thread-local state by using Spring Web’s
RequestContextHolder before each test method and creates a MockHttpServletRequest, a MockHttpServletResponse, and
a ServletWebRequest based on the base resource path configured with @WebAppConfiguration.
ServletTestExecutionListener also ensures that the MockHttpServletResponse and ServletWebRequest can be injected
into the test instance, and, once the test is complete, it cleans up thread-local state.
为了提供全面的 Web 测试支持,TestContext 框架默认启用了 ServletTestExecutionListener 。当针对 WebApplicationContext
进行测试时,此 TestExecutionListener 通过使用 Spring Web 的 RequestContextHolder 在每个测试方法之前设置默认的线程局部状态,并基于使用
@WebAppConfiguration 配置的基础资源路径创建一个 MockHttpServletRequest 、一个 MockHttpServletResponse 和一个
ServletWebRequest 。 ServletTestExecutionListener 还确保 MockHttpServletResponse 和 ServletWebRequest
可以被注入到测试实例中,并且一旦测试完成,它将清理线程局部状态。
Once you have a WebApplicationContext loaded for your test, you might find that you need to interact with the web
mocks — for example, to set up your test fixture or to perform assertions after invoking your web component. The
following example shows which mocks can be autowired into your test instance.
一旦为您的测试加载了 WebApplicationContext ,您可能会发现您需要与 Web 模拟进行交互——例如,设置您的测试环境或调用您的 Web
组件后执行断言。以下示例显示了哪些模拟可以自动注入到您的测试实例中。
Note that the WebApplicationContext and MockServletContext are both cached across the test suite, whereas the other
mocks are managed per test method by the ServletTestExecutionListener.
请注意, WebApplicationContext 和 MockServletContext 都在测试套件中进行了缓存,而其他模拟对象则由
ServletTestExecutionListener 在每个测试方法中管理。
Once the TestContext framework loads an ApplicationContext (or WebApplicationContext) for a test, that context is
cached and reused for all subsequent tests that declare the same unique context configuration within the same test
suite. To understand how caching works, it is important to understand what is meant by “unique” and “test suite.”
一旦 TestContext 框架加载了一个测试的 ApplicationContext (或 WebApplicationContext
),该上下文就会被缓存并用于同一测试套件中声明相同唯一上下文配置的所有后续测试。要理解缓存的工作原理,重要的是要了解“唯一”和“测试套件”的含义。
An ApplicationContext can be uniquely identified by the combination of configuration parameters that is used to load
it. Consequently, the unique combination of configuration parameters is used to generate a key under which the context
is cached.
一个 ApplicationContext
可以通过用于加载它的配置参数的组合来唯一标识。因此,使用唯一的配置参数组合来生成一个键,在哪个键下缓存上下文。
The TestContext framework uses the following configuration parameters to build the context cache key:
测试上下文框架使用以下配置参数来构建上下文缓存键:
locations (from @ContextConfiguration)locations (来自 @ContextConfiguration )
classes (from @ContextConfiguration)classes (来自 @ContextConfiguration )
contextInitializerClasses (from @ContextConfiguration)contextInitializerClasses (来自 @ContextConfiguration )
contextCustomizers (from ContextCustomizerFactory) – this includes @DynamicPropertySource methods as well as
various features from Spring Boot’s testing support such as @MockBean and @SpyBean.
contextCustomizers (来自 ContextCustomizerFactory )- 这包括 @DynamicPropertySource 方法以及 Spring Boot
测试支持的各种功能,如 @MockBean 和 @SpyBean 。
contextLoader (from @ContextConfiguration)contextLoader (来自 @ContextConfiguration )
parent (from @ContextHierarchy)parent (来自 @ContextHierarchy )
activeProfiles (from @ActiveProfiles)activeProfiles (来自 @ActiveProfiles )
propertySourceLocations (from @TestPropertySource)propertySourceLocations (来自 @TestPropertySource )
propertySourceProperties (from @TestPropertySource)propertySourceProperties (来自 @TestPropertySource )
resourceBasePath (from @WebAppConfiguration)resourceBasePath (来自 @WebAppConfiguration )
For example, if TestClassA specifies {"app-config.xml", "test-config.xml"} for the locations (or value)
attribute of @ContextConfiguration, the TestContext framework loads the corresponding ApplicationContext and stores
it in a static context cache under a key that is based solely on those locations. So, if TestClassB also defines
{"app-config.xml", "test-config.xml"} for its locations (either explicitly or implicitly through inheritance) but does
not define @WebAppConfiguration, a different ContextLoader, different active profiles, different context
initializers, different test property sources, or a different parent context, then the same ApplicationContext is
shared by both test classes. This means that the setup cost for loading an application context is incurred only once (
per test suite), and subsequent test execution is much faster.
例如,如果 TestClassA 指定了 {"app-config.xml", "test-config.xml"} 的 locations (或 value )属性为
@ContextConfiguration ,TestContext 框架将加载相应的 ApplicationContext 并将其存储在基于这些位置的 static
上下文缓存中。因此,如果 TestClassB 也为其位置定义了 {"app-config.xml", "test-config.xml"} (无论是显式还是通过继承隐式定义),但没有定义
@WebAppConfiguration ,则不同的 ContextLoader 、不同的活动配置文件、不同的上下文初始化器、不同的测试属性源或不同的父上下文,那么相同的
ApplicationContext 将由两个测试类共享。这意味着加载应用程序上下文的设置成本(每个测试套件)仅发生一次,后续的测试执行速度会更快。
Test suites and forked processes
测试套件和分叉进程
The Spring TestContext framework stores application contexts in a static cache. This means that the context is literally
stored in a static variable. In other words, if tests run in separate processes, the static cache is cleared between
each test execution, which effectively disables the caching mechanism.
Spring TestContext 框架将应用程序上下文存储在静态缓存中。这意味着上下文实际上存储在一个 static
变量中。换句话说,如果测试在单独的进程中运行,静态缓存将在每次测试执行之间清除,这实际上禁用了缓存机制。
To benefit from the caching mechanism, all tests must run within the same process or test suite. This can be achieved by
executing all tests as a group within an IDE.
为了从缓存机制中受益,所有测试必须在同一进程中或测试套件中运行。这可以通过在 IDE 中将所有测试作为一个组执行来实现。
Similarly, when executing tests with a build framework such as Ant, Maven, or Gradle, it is important to make sure that
the build framework does not fork between tests. For example, if the
forkMode for the Maven Surefire
plug-in is set to always or pertest, the TestContext framework cannot cache application contexts between test
classes, and the build process runs significantly more slowly as a result.
同样,当使用 Ant、Maven 或 Gradle 等构建框架执行测试时,确保构建框架在测试之间不进行分支是很重要的。例如,如果 Maven Surefire
插件的 forkMode 设置为 always 或 pertest ,则 TestContext 框架无法在测试类之间缓存应用程序上下文,因此构建过程会显著变慢。
The size of the context cache is bounded with a default maximum size of 32. Whenever the maximum size is reached, a
least recently used (LRU) eviction policy is used to evict and close stale contexts.
上下文缓存的尺寸受限于默认最大值 32。当达到最大尺寸时,使用最近最少使用(LRU)驱逐策略来驱逐和关闭过时的上下文。
You can configure the maximum size from the command line or a build script by setting a JVM system property named
spring.test.context.cache.maxSize. As an alternative, you can set the same property via the
SpringProperties
mechanism.
您可以通过设置名为 spring.test.context.cache.maxSize 的 JVM 系统属性,从命令行或构建脚本中配置最大大小。作为替代,您也可以通过
SpringProperties 机制设置相同的属性。
Since having a large number of application contexts loaded within a given test suite can cause the suite to take an
unnecessarily long time to run, it is often beneficial to know exactly how many contexts have been loaded and cached.
由于在给定的测试套件中加载大量应用程序上下文可能会导致套件运行时间过长,因此了解确切加载了多少上下文和缓存通常是有益的。
To view the statistics for the underlying context cache, you can set the log level for the
org.springframework.test.context.cache logging category to DEBUG.
查看底层上下文缓存的统计信息,您可以设置 org.springframework.test.context.cache 日志类别的日志级别为 DEBUG 。
In the unlikely case that a test corrupts the application context and requires reloading (for example, by modifying a
bean definition or the state of an application object), you can annotate your test class or test method with
@DirtiesContext (see the discussion of @DirtiesContext
in Spring Testing Annotations). This instructs Spring to remove the context
from the cache and rebuild the application context before running the next test that requires the same application
context. Note that support for the @DirtiesContext annotation is provided by the
DirtiesContextBeforeModesTestExecutionListener and the DirtiesContextTestExecutionListener, which are enabled by
default.
在不太可能的情况下,如果测试破坏了应用程序上下文并需要重新加载(例如,通过修改 bean 定义或应用程序对象的状态),您可以在测试类或测试方法上使用
@DirtiesContext 注解(有关 @DirtiesContext 的讨论请参阅 Spring 测试注解)。这指示 Spring
在运行下一个需要相同应用程序上下文的测试之前,从缓存中删除上下文并重新构建应用程序上下文。请注意, @DirtiesContext 注解的支持由
DirtiesContextBeforeModesTestExecutionListener 和 DirtiesContextTestExecutionListener 提供,这些默认启用。
ApplicationContext lifecycle and console logging
应用程序上下文生命周期和控制台日志
When you need to debug a test executed with the Spring TestContext Framework, it can be useful to analyze the console
output (that is, output to the SYSOUT and SYSERR streams). Some build tools and IDEs are able to associate console
output with a given test; however, some console output cannot be easily associated with a given test.
当您需要调试使用 Spring TestContext 框架执行的测试时,分析控制台输出(即输出到 SYSOUT 和 SYSERR 流)可能很有用。一些构建工具和
IDE 能够将控制台输出与特定的测试关联起来;然而,某些控制台输出难以与特定的测试关联。
With regard to console logging triggered by the Spring Framework itself or by components registered in the
ApplicationContext, it is important to understand the lifecycle of an ApplicationContext that has been loaded by the
Spring TestContext Framework within a test suite.
关于由 Spring 框架本身或注册在 ApplicationContext 中的组件触发的控制台日志,了解在测试套件中由 Spring TestContext 框架加载的
ApplicationContext 的生命周期非常重要。
The ApplicationContext for a test is typically loaded when an instance of the test class is being prepared — for
example, to perform dependency injection into @Autowired fields of the test instance. This means that any console
logging triggered during the initialization of the ApplicationContext typically cannot be associated with an
individual test method. However, if the context is closed immediately before the execution of a test method according
to @DirtiesContext semantics, a new instance of the context will be
loaded just prior to execution of the test method. In the latter scenario, an IDE or build tool may potentially
associate console logging with the individual test method.
测试的 ApplicationContext 通常在准备测试类实例时加载——例如,将依赖注入到测试实例的 @Autowired 字段中。这意味着在
ApplicationContext 初始化期间触发的任何控制台日志通常无法与单个测试方法关联。然而,如果根据 @DirtiesContext
语义在执行测试方法之前立即关闭上下文,则在执行测试方法之前将加载新的上下文实例。在后一种情况下,IDE 或构建工具可能将控制台日志与单个测试方法关联。
The ApplicationContext for a test can be closed via one of the following scenarios.
测试的 ApplicationContext 可以通过以下任一场景关闭。
The context is closed according to @DirtiesContext semantics.
上下文根据 @DirtiesContext 语义关闭。
The context is closed because it has been automatically evicted from the cache according to the LRU eviction policy.
上下文已关闭,因为它根据 LRU 淘汰策略被自动从缓存中移除。
The context is closed via a JVM shutdown hook when the JVM for the test suite terminates.
测试套件的 JVM 终止时,通过 JVM 关闭钩子关闭上下文。
If the context is closed according to @DirtiesContext semantics after a particular test method, an IDE or build tool
may potentially associate console logging with the individual test method. If the context is closed according to
@DirtiesContext semantics after a test class, any console logging triggered during the shutdown of the
ApplicationContext cannot be associated with an individual test method. Similarly, any console logging triggered
during the shutdown phase via a JVM shutdown hook cannot be associated with an individual test method.
如果在特定测试方法之后根据 @DirtiesContext 语义关闭上下文,IDE 或构建工具可能会将控制台日志与单个测试方法关联起来。如果在测试类之后根据
@DirtiesContext 语义关闭上下文,任何在 ApplicationContext 关闭期间触发的控制台日志都无法与单个测试方法关联。同样,在
JVM 关闭钩子期间触发的任何控制台日志也无法与单个测试方法关联。
When a Spring ApplicationContext is closed via a JVM shutdown hook, callbacks executed during the shutdown phase are
executed on a thread named SpringContextShutdownHook. So, if you wish to disable console logging triggered when the
ApplicationContext is closed via a JVM shutdown hook, you may be able to register a custom filter with your logging
framework that allows you to ignore any logging initiated by that thread.
当通过 JVM 关闭钩子关闭 Spring ApplicationContext 时,在关闭阶段执行的回调将在名为 SpringContextShutdownHook
的线程上执行。因此,如果您希望禁用通过 JVM 关闭钩子关闭 ApplicationContext
时触发的控制台日志,您可能能够注册一个自定义过滤器,以便您能够忽略由该线程发起的任何日志记录。
When writing integration tests that rely on a loaded Spring ApplicationContext, it is often sufficient to test against
a single context. However, there are times when it is beneficial or even necessary to test against a hierarchy of
ApplicationContext instances. For example, if you are developing a Spring MVC web application, you typically have a
root WebApplicationContext loaded by Spring’s ContextLoaderListener and a child WebApplicationContext loaded by
Spring’s DispatcherServlet. This results in a parent-child context hierarchy where shared components and
infrastructure configuration are declared in the root context and consumed in the child context by web-specific
components.
编写依赖于已加载的 Spring ApplicationContext 的集成测试时,通常只需要针对单个上下文进行测试。然而,有时针对实例层次结构进行测试是有益的,甚至可能是必要的。例如,如果您正在开发
Spring MVC Web 应用程序,通常会有一个由 Spring 的 ContextLoaderListener 加载的根 WebApplicationContext 和一个由
Spring 的 DispatcherServlet 加载的子 WebApplicationContext 。这导致了一个父子上下文层次结构,其中共享组件和基础设施配置在根上下文中声明,并由
Web 特定组件在子上下文中消费。
Another use case can be found in Spring Batch applications, where you often have a parent context that provides
configuration for shared batch infrastructure and a child context for the configuration of a specific batch job.
另一个用例可以在 Spring Batch 应用程序中找到,其中通常有一个父上下文提供共享批处理基础设施的配置,以及一个子上下文用于特定批处理作业的配置。
You can write integration tests that use context hierarchies by declaring context configuration with the
@ContextHierarchy annotation, either on an individual test class or within a test class hierarchy. If a context
hierarchy is declared on multiple classes within a test class hierarchy, you can also merge or override the context
configuration for a specific, named level in the context hierarchy.
您可以通过使用 @ContextHierarchy
注解声明上下文配置来编写使用上下文层次结构的集成测试,这可以在单个测试类中,或者在测试类层次结构内部进行。如果在测试类层次结构中的多个类上声明了上下文层次结构,您还可以合并或覆盖上下文层次结构中特定命名级别的上下文配置。
When merging configuration for a given level in the hierarchy, the configuration resource type (that is, XML
configuration files or component classes) must be consistent.
在合并层次结构中给定级别的配置时,配置资源类型(即 XML 配置文件或组件类)必须保持一致。
Otherwise, it is perfectly acceptable to have different levels in a context hierarchy configured using different
resource types.
否则,在上下文层次结构中使用不同资源类型配置不同级别是完全可接受的。
The remaining JUnit Jupiter based examples in this section show common configuration scenarios for integration tests
that require the use of context hierarchies.
本节剩余的基于 JUnit Jupiter 的示例展示了需要使用上下文层次结构的集成测试的常见配置场景。
Single test class with context hierarchy
单个测试类与上下文层次结构
ControllerIntegrationTests represents a typical integration testing scenario for a Spring MVC web application by
declaring a context hierarchy that consists of two levels, one for the root WebApplicationContext (loaded by using the
TestAppConfig @Configuration class) and one for the dispatcher servlet WebApplicationContext (loaded by using the
WebConfig @Configuration class). The WebApplicationContext that is autowired into the test instance is the one for
the child context (that is, the lowest context in the hierarchy). The following listing shows this configuration
scenario:
ControllerIntegrationTests 代表通过声明由两个级别组成的上下文层次结构,一个用于根 WebApplicationContext (通过使用
TestAppConfig @Configuration 类加载),另一个用于分发器 servlet WebApplicationContext (通过使用 WebConfig
@Configuration 类加载),来表示一个典型的 Spring MVC 网络应用程序的集成测试场景。自动装配到测试实例中的
WebApplicationContext 是子上下文(即层次结构中的最低上下文)。以下列表显示了此配置场景:
Class hierarchy with implicit parent context
类层次结构,具有隐式父上下文
The test classes in this example define a context hierarchy within a test class hierarchy. AbstractWebTests declares
the configuration for a root WebApplicationContext in a Spring-powered web application. Note, however, that
AbstractWebTests does not declare @ContextHierarchy. Consequently, subclasses of AbstractWebTests can optionally
participate in a context hierarchy or follow the standard semantics for @ContextConfiguration. SoapWebServiceTests
and RestWebServiceTests both extend AbstractWebTests and define a context hierarchy by using @ContextHierarchy.
The result is that three application contexts are loaded (one for each declaration of @ContextConfiguration), and the
application context loaded based on the configuration in AbstractWebTests is set as the parent context for each of the
contexts loaded for the concrete subclasses. The following listing shows this configuration scenario:
该示例中的测试类在测试类层次结构中定义了一个上下文层次结构。 AbstractWebTests 声明了一个由 Spring 驱动的 Web 应用程序中的根
WebApplicationContext 的配置。请注意, AbstractWebTests 并未声明 @ContextHierarchy 。因此, AbstractWebTests
的子类可以选择性地参与上下文层次结构或遵循 @ContextConfiguration 的标准语义。 SoapWebServiceTests 和
RestWebServiceTests 都扩展了 AbstractWebTests 并通过使用 @ContextHierarchy 定义了一个上下文层次结构。结果是加载了三个应用程序上下文(每个
@ContextConfiguration 的声明对应一个),基于 AbstractWebTests 中的配置加载的应用程序上下文被设置为为每个为具体子类加载的上下文的父上下文。以下列表显示了此配置场景:
Class hierarchy with merged context hierarchy configuration
类层次结构以及合并的上下文层次结构配置
The classes in this example show the use of named hierarchy levels in order to merge the configuration for specific
levels in a context hierarchy. BaseTests defines two levels in the hierarchy, parent and child. ExtendedTests
extends BaseTests and instructs the Spring TestContext Framework to merge the context configuration for the child
hierarchy level, by ensuring that the names declared in the name attribute in @ContextConfiguration are both
child. The result is that three application contexts are loaded: one for /app-config.xml, one for
/user-config.xml, and one for {"/user-config.xml", "/order-config.xml"}. As with the previous example, the
application context loaded from /app-config.xml is set as the parent context for the contexts loaded from
/user-config.xml and {"/user-config.xml", "/order-config.xml"}. The following listing shows this configuration
scenario:
本例中的类展示了使用命名层次级别来合并上下文层次中特定级别的配置。 BaseTests 定义了层次结构中的两个级别, parent 和
child 。 ExtendedTests 扩展了 BaseTests 并指示 Spring 测试上下文框架合并 child 层次级别的上下文配置,通过确保
@ContextConfiguration 中的 name 属性中声明的名称都是 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"}
加载的上下文的父上下文。以下列表显示了此配置场景:
Class hierarchy with overridden context hierarchy configuration
类层次结构,具有覆盖的上下文层次结构配置
In contrast to the previous example, this example demonstrates how to override the configuration for a given named level
in a context hierarchy by setting the inheritLocations flag in @ContextConfiguration to false. Consequently, the
application context for ExtendedTests is loaded only from /test-user-config.xml and has its parent set to the
context loaded from /app-config.xml. The following listing shows this configuration scenario:
与上一个示例相比,本例演示了如何通过将 @ContextConfiguration 中的 inheritLocations 标志设置为 false
来覆盖上下文层次结构中给定命名级别的配置。因此,仅从 /test-user-config.xml 加载 ExtendedTests 的应用程序上下文,并将其父上下文设置为从
/app-config.xml 加载的上下文。以下列表显示了此配置场景:
Dirtying a context within a context hierarchy
污染上下文层次结构中的上下文
If you use @DirtiesContext in a test whose context is configured as part of a context hierarchy, you can use the
hierarchyMode flag to control how the context cache is cleared. For further details, see the discussion of
@DirtiesContext in Spring Testing Annotations and the
@DirtiesContext
javadoc.
如果您在一个配置为上下文层次结构一部分的测试中使用 @DirtiesContext ,您可以使用 hierarchyMode
标志来控制上下文缓存如何被清除。有关详细信息,请参阅 Spring Testing Annotations 中对 @DirtiesContext 的讨论以及
@DirtiesContext 的 javadoc。
3.5.7. 测试固件的依赖注入
When you use the DependencyInjectionTestExecutionListener (which is configured by default), the dependencies of your
test instances are injected from beans in the application context that you configured with @ContextConfiguration or
related annotations. You may use setter injection, field injection, or both, depending on which annotations you choose
and whether you place them on setter methods or fields. If you are using JUnit Jupiter you may also optionally use
constructor injection (see Dependency Injection with SpringExtension). For
consistency with Spring’s annotation-based injection support, you may also use Spring’s @Autowired annotation or the
@Inject annotation from JSR-330 for field and setter injection.
当你使用默认配置的 DependencyInjectionTestExecutionListener 时,你的测试实例的依赖项将从你使用 @ContextConfiguration
或相关注解配置的应用程序上下文中的 bean 中注入。你可以使用 setter 注入、field 注入或两者都使用,具体取决于你选择的注解以及你是否将它们放在
setter 方法或字段上。如果你使用 JUnit Jupiter,你也可以选择性地使用构造函数注入(见使用 SpringExtension 的依赖注入)。为了与
Spring 基于注解的注入支持保持一致,你也可以使用 Spring 的 @Autowired 注解或 JSR-330 的 @Inject 注解进行 field 和
setter 注入。
For testing frameworks other than JUnit Jupiter, the TestContext framework does not participate in instantiation of the
test class. Thus, the use of @Autowired or @Inject for constructors has no effect for test classes.
对于 JUnit Jupiter 以外的测试框架,TestContext 框架不参与测试类的实例化。因此,对于测试类,使用 @Autowired 或 @Inject
构造函数没有效果。
Although field injection is discouraged in production code, field injection is actually quite natural in test code. The
rationale for the difference is that you will never instantiate your test class directly. Consequently, there is no need
to be able to invoke a public constructor or setter method on your test class.
尽管在生产代码中不建议使用字段注入,但在测试代码中,字段注入实际上相当自然。这种差异的原因是您永远不会直接实例化您的测试类。因此,您不需要能够在您的测试类上调用构造函数或
setter 方法。
Because @Autowired is used to
perform autowiring by type,
if you have multiple bean definitions of the same type, you cannot rely on this approach for those particular beans. In
that case, you can use @Autowired in conjunction with @Qualifier. You can also choose to use @Inject in
conjunction with @Named. Alternatively, if your test class has access to its ApplicationContext, you can perform an
explicit lookup by using (for example) a call to
applicationContext.getBean("titleRepository", TitleRepository.class).
因为 @Autowired 用于通过类型执行自动装配,如果您有多个相同类型的 bean 定义,您不能依赖这种方法来处理这些特定的
bean。在这种情况下,您可以使用 @Autowired 结合 @Qualifier 。您也可以选择使用 @Inject 结合 @Named 。或者,如果您的测试类可以访问其
ApplicationContext ,您可以通过(例如)调用 applicationContext.getBean("titleRepository", TitleRepository.class)
来执行显式查找。
If you do not want dependency injection applied to your test instances, do not annotate fields or setter methods with
@Autowired or @Inject. Alternatively, you can disable dependency injection altogether by explicitly configuring your
class with @TestExecutionListeners and omitting DependencyInjectionTestExecutionListener.class from the list of
listeners.
如果您不想将依赖注入应用于测试实例,请不要使用 @Autowired 或 @Inject 注解字段或 setter 方法。或者,您可以通过使用
@TestExecutionListeners 显式配置您的类并从监听器列表中省略 DependencyInjectionTestExecutionListener.class 来完全禁用依赖注入。
Consider the scenario of testing a HibernateTitleRepository class, as outlined in
the Goals section. The next two code listings demonstrate the use of @Autowired on
fields and setter methods. The application context configuration is presented after all sample code listings.
考虑测试 HibernateTitleRepository 类的场景,如目标部分所述。接下来的两个代码示例展示了在字段和设置方法中使用
@Autowired 。在所有示例代码之后,展示了应用程序上下文配置。
The dependency injection behavior in the following code listings is not specific to JUnit Jupiter. The same DI
techniques can be used in conjunction with any supported testing framework.
以下代码示例中的依赖注入行为并不仅限于 JUnit Jupiter。相同的 DI 技术可以与任何支持的测试框架结合使用。
The following examples make calls to static assertion methods, such as assertNotNull(), but without prepending the
call with Assertions. In such cases, assume that the method was properly imported through an import static
declaration that is not shown in the example.
以下示例调用静态断言方法,如 assertNotNull() ,但未在调用前添加 Assertions 。在这种情况下,假设该方法已通过未在示例中显示的
import static 声明正确导入。
The first code listing shows a JUnit Jupiter based implementation of the test class that uses @Autowired for field
injection:
第一段代码列表展示了基于 JUnit Jupiter 的测试类实现,该实现使用 @Autowired 进行字段注入:
Alternatively, you can configure the class to use @Autowired for setter injection, as follows:
或者,您可以配置类使用 @Autowired 进行 setter 注入,如下所示:
The preceding code listings use the same XML context file referenced by the @ContextConfiguration annotation (that is,
repository-config.xml). The following shows this configuration:
前述代码列表使用与 @ContextConfiguration 注释引用相同的 XML 上下文文件(即, repository-config.xml )。以下显示了此配置:
If you are extending from a Spring-provided test base class that happens to use @Autowired on one of its setter
methods, you might have multiple beans of the affected type defined in your application context (for example, multiple
DataSource beans). In such a case, you can override the setter method and use the @Qualifier annotation to indicate
a specific target bean, as follows (but make sure to delegate to the overridden method in the superclass as well):
The specified qualifier value indicates the specific DataSource bean to inject, narrowing the set of type matches to a
specific bean. Its value is matched against <qualifier> declarations within the corresponding <bean> definitions.
The bean name is used as a fallback qualifier value, so you can effectively also point to a specific bean by name
there (as shown earlier, assuming that myDataSource is the bean id).
Spring has supported Request- and session-scoped beans since the early years, and you can test your request-scoped and session-scoped beans by following these steps:
Ensure that a WebApplicationContext is loaded for your test by annotating your test class with
@WebAppConfiguration.
Inject the mock request or session into your test instance and prepare your test fixture as appropriate.
Invoke your web component that you retrieved from the configured WebApplicationContext (with dependency injection).
Perform assertions against the mocks.
The next code snippet shows the XML configuration for a login use case. Note that the userService bean has a
dependency on a request-scoped loginAction bean. Also, the LoginAction is instantiated by
using SpEL expressions that
retrieve the username and password from the current HTTP request. In our test, we want to configure these request
parameters through the mock managed by the TestContext framework. The following listing shows the configuration for this
use case:
下一段代码片段显示了登录用例的 XML 配置。请注意, userService bean 依赖于一个请求作用域的 loginAction bean。此外,
LoginAction 是通过使用 SpEL 表达式实例化的,这些表达式从当前 HTTP 请求中检索用户名和密码。在我们的测试中,我们希望通过
TestContext 框架管理的模拟来配置这些请求参数。以下列表显示了此用例的配置:
Request-scoped bean configuration
请求作用域的 Bean 配置
In RequestScopedBeanTests, we inject both the UserService (that is, the subject under test) and the
MockHttpServletRequest into our test instance. Within our requestScope() test method, we set up our test fixture by
setting request parameters in the provided MockHttpServletRequest. When the loginUser() method is invoked on our
userService, we are assured that the user service has access to the request-scoped loginAction for the current
MockHttpServletRequest (that is, the one in which we just set parameters). We can then perform assertions against the
results based on the known inputs for the username and password. The following listing shows how to do so:
在 RequestScopedBeanTests 中,我们将 UserService (即受测试的主题)和 MockHttpServletRequest 注入到我们的测试实例中。在我们的
requestScope() 测试方法中,通过设置提供的 MockHttpServletRequest 中的请求参数来设置测试环境。当在 userService 上调用
loginUser() 方法时,我们确保用户服务可以访问当前 MockHttpServletRequest (即我们刚刚设置参数的那个)的请求作用域中的
loginAction 。然后,我们可以根据已知的用户名和密码输入对结果进行断言。以下列表显示了如何这样做:
The following code snippet is similar to the one we saw earlier for a request-scoped bean. However, this time, the
userService bean has a dependency on a session-scoped userPreferences bean. Note that the UserPreferences bean is
instantiated by using a SpEL expression that retrieves the theme from the current HTTP session. In our test, we need to
configure a theme in the mock session managed by the TestContext framework. The following example shows how to do so:
以下代码片段与之前我们看到的请求作用域的 bean 类似。然而,这次 userService bean 依赖于会话作用域的 userPreferences
bean。请注意, UserPreferences bean 是通过使用 SpEL 表达式从当前 HTTP 会话中检索主题来实例化的。在我们的测试中,我们需要配置一个由
TestContext 框架管理的模拟会话中的主题。以下示例展示了如何做到这一点:
Session-scoped bean configuration
会话作用域的 Bean 配置
In SessionScopedBeanTests, we inject the UserService and the MockHttpSession into our test instance. Within our
sessionScope() test method, we set up our test fixture by setting the expected theme attribute in the provided
MockHttpSession. When the processUserPreferences() method is invoked on our userService, we are assured that the
user service has access to the session-scoped userPreferences for the current MockHttpSession, and we can perform
assertions against the results based on the configured theme. The following example shows how to do so:
在 SessionScopedBeanTests 中,我们将 UserService 和 MockHttpSession 注入到我们的测试实例中。在我们的
sessionScope() 测试方法中,我们通过设置提供的 MockHttpSession 中的预期 theme 属性来设置测试环境。当在 userService
上调用 processUserPreferences() 方法时,我们确保用户服务可以访问当前 MockHttpSession 的会话作用域的 userPreferences
,并且我们可以根据配置的主题对结果进行断言。以下示例展示了如何做到这一点:
3.5.9. 事务管理
In the TestContext framework, transactions are managed by the TransactionalTestExecutionListener, which is configured
by default, even if you do not explicitly declare @TestExecutionListeners on your test class. To enable support for
transactions, however, you must configure a PlatformTransactionManager bean in the ApplicationContext that is loaded
with @ContextConfiguration semantics (further details are provided later). In addition, you must declare Spring’s
@Transactional annotation either at the class or the method level for your tests.
在 TestContext 框架中,事务由 TransactionalTestExecutionListener 管理,默认配置,即使你不在你的测试类中显式声明
@TestExecutionListeners 。然而,为了启用事务支持,你必须配置一个在 ApplicationContext 中加载了 @ContextConfiguration
语义的 PlatformTransactionManager bean(更详细的信息将在后面提供)。此外,你必须在你测试的类或方法级别声明 Spring 的
@Transactional 注解。
测试管理事务
Test-managed transactions are transactions that are managed declaratively by using the
TransactionalTestExecutionListener or programmatically by using TestTransaction (described later). You should not
confuse such transactions with Spring-managed transactions (those managed directly by Spring within the
ApplicationContext loaded for tests) or application-managed transactions (those managed programmatically within
application code that is invoked by tests). Spring-managed and application-managed transactions typically participate in
test-managed transactions.
测试管理的交易是通过使用 TransactionalTestExecutionListener 声明式管理或使用 TestTransaction
(稍后描述)程序化管理的交易。您不应将这些交易与 Spring 管理的交易(在为测试加载的 ApplicationContext 内由 Spring
直接管理的交易)或应用管理的交易(在由测试调用的应用代码内程序化管理的交易)混淆。Spring
管理的交易和应用管理的交易通常参与测试管理的交易。
However, you should use caution if Spring-managed or application-managed transactions are configured with any
propagation type other than REQUIRED or SUPPORTS (see the discussion
on transaction propagation
for details).
然而,如果您配置了除 REQUIRED 或 SUPPORTS 之外的其他传播类型,则在使用 Spring 管理的或应用程序管理的事务时应该谨慎(有关事务传播的讨论请参阅详细信息)。
Preemptive timeouts and test-managed transactions
预防性超时和测试管理事务
Caution must be taken when using any form of preemptive timeouts from a testing framework in conjunction with Spring’s
test-managed transactions.
在使用测试框架中的任何形式的预置超时与 Spring 的测试管理事务结合时必须谨慎。
Specifically, Spring’s testing support binds transaction state to the current thread (via a java.lang.ThreadLocal
variable) before the current test method is invoked. If a testing framework invokes the current test method in a new
thread in order to support a preemptive timeout, any actions performed within the current test method will not be
invoked within the test-managed transaction. Consequently, the result of any such actions will not be rolled back with
the test-managed transaction.
具体来说,Spring 的测试支持在调用当前测试方法之前,将事务状态绑定到当前线程(通过一个 java.lang.ThreadLocal
变量)。如果测试框架在一个新线程中调用当前测试方法以支持抢占式超时,则当前测试方法中执行的操作将不会在测试管理的事务中执行。因此,此类操作的结果将不会与测试管理的事务回滚。
On the contrary, such actions will be committed to the persistent store — for example, a relational database — even
though the test-managed transaction is properly rolled back by Spring.
相反,此类操作将被提交到持久存储——例如,关系数据库——即使 Spring 正确地回滚了测试管理的事务。
Situations in which this can occur include but are not limited to the following.
这种情况可能发生的场景包括但不限于以下内容。
JUnit 4’s @Test(timeout = …) support and TimeOut rule
JUnit 4 的 @Test(timeout = …) 支持和 TimeOut 规则
JUnit Jupiter’s assertTimeoutPreemptively(…) methods in the org.junit.jupiter.api.Assertions class
JUnit Jupiter 类中的 assertTimeoutPreemptively(…) 方法
TestNG’s @Test(timeOut = …) support TestNG 的 @Test(timeOut = …) 支持
启用和禁用事务
Annotating a test method with @Transactional causes the test to be run within a transaction that is, by default,
automatically rolled back after completion of the test. If a test class is annotated with @Transactional, each test
method within that class hierarchy runs within a transaction. Test methods that are not annotated with
@Transactional (at the class or method level) are not run within a transaction. Note that @Transactional is not
supported on test lifecycle methods — for example, methods annotated with JUnit Jupiter’s @BeforeAll, @BeforeEach,
etc. Furthermore, tests that are annotated with @Transactional but have the propagation attribute set to
NOT_SUPPORTED or NEVER are not run within a transaction.
为测试方法添加 @Transactional 注解会导致测试在默认情况下在事务中运行,并在测试完成后自动回滚。如果一个测试类被添加了
@Transactional 注解,该类层次结构中的每个测试方法都在事务中运行。未添加 @Transactional (在类或方法级别)注解的测试方法不在事务中运行。请注意,
@Transactional 不支持在测试生命周期方法上——例如,使用 JUnit Jupiter 的 @BeforeAll 、 @BeforeEach 等注解的方法。此外,添加了
@Transactional 注解但将 propagation 属性设置为 NOT_SUPPORTED 或 NEVER 的测试不会在事务中运行。
Table 1. @Transactional attribute support
表 1. @Transactional 属性支持
Attribute 属性
Supported for test-managed transactions
支持测试管理事务
value and transactionManager``value 和 transactionManager
yes 是的
propagation
only Propagation.NOT_SUPPORTED and Propagation.NEVER are supported
仅支持 Propagation.NOT_SUPPORTED 和 Propagation.NEVER
isolation
no 无
timeout
no 无
readOnly
no 无
rollbackFor and rollbackForClassName``rollbackFor 和 rollbackForClassName
no: use TestTransaction.flagForRollback() instead 无需翻译
noRollbackFor and noRollbackForClassName``noRollbackFor 和 noRollbackForClassName
no: use TestTransaction.flagForCommit() instead 无需翻译
Method-level lifecycle methods — for example, methods annotated with JUnit Jupiter’s @BeforeEach or @AfterEach — are
run within a test-managed transaction. On the other hand, suite-level and class-level lifecycle methods — for example,
methods annotated with JUnit Jupiter’s @BeforeAll or @AfterAll and methods annotated with TestNG’s @BeforeSuite,
@AfterSuite, @BeforeClass, or @AfterClass — are not run within a test-managed transaction.
方法级别的生命周期方法——例如,使用 JUnit Jupiter 的 @BeforeEach 或 @AfterEach
注解的方法——在测试管理的事务中运行。另一方面,套件级别和类级别的生命周期方法——例如,使用 JUnit Jupiter 的 @BeforeAll 或
@AfterAll 注解的方法以及使用 TestNG 的 @BeforeSuite 、 @AfterSuite 、 @BeforeClass 或 @AfterClass
注解的方法——不在测试管理的事务中运行。
If you need to run code in a suite-level or class-level lifecycle method within a transaction, you may wish to inject a
corresponding PlatformTransactionManager into your test class and then use that with a TransactionTemplate for
programmatic transaction management.
如果您需要在事务中的套件级别或类级别生命周期方法中运行代码,您可能希望将相应的 PlatformTransactionManager
注入到您的测试类中,然后使用 TransactionTemplate 进行程序化事务管理。
Note that AbstractTransactionalJUnit4SpringContextTests and
AbstractTransactionalTestNGSpringContextTests are preconfigured for
transactional support at the class level.
请注意, AbstractTransactionalJUnit4SpringContextTests 和 AbstractTransactionalTestNGSpringContextTests
在类级别上已预配置以支持事务。
The following example demonstrates a common scenario for writing an integration test for a Hibernate-based
UserRepository:
以下示例演示了编写基于 Hibernate 的集成测试的常见场景
As explained in Transaction Rollback and Commit Behavior, there is no
need to clean up the database after the createUser() method runs, since any changes made to the database are
automatically rolled back by the TransactionalTestExecutionListener.
如《事务回滚和提交行为》中所述,在 createUser() 方法运行后无需清理数据库,因为对数据库所做的任何更改都会自动由
TransactionalTestExecutionListener 回滚。
事务回滚和提交行为
By default, test transactions will be automatically rolled back after completion of the test; however, transactional
commit and rollback behavior can be configured declaratively via the @Commit and @Rollback annotations. See the
corresponding entries in the annotation support section for further details.
默认情况下,测试事务将在测试完成后自动回滚;然而,可以通过 @Commit 和 @Rollback
注解声明式地配置事务提交和回滚行为。请参阅注解支持部分的相应条目以获取更多详细信息。
程序化事务管理
You can interact with test-managed transactions programmatically by using the static methods in TestTransaction. For
example, you can use TestTransaction within test methods, before methods, and after methods to start or end the
current test-managed transaction or to configure the current test-managed transaction for rollback or commit. Support
for TestTransaction is automatically available whenever the TransactionalTestExecutionListener is enabled.
您可以通过使用 TestTransaction 中的静态方法以编程方式与测试管理的交易进行交互。例如,您可以在测试方法中、方法之前和方法之后使用
TestTransaction 来启动或结束当前测试管理的交易,或者配置当前测试管理的交易以进行回滚或提交。当
TransactionalTestExecutionListener 启用时,对 TestTransaction 的支持将自动可用。
The following example demonstrates some of the features of TestTransaction. See the javadoc for
TestTransaction
for further details.
以下示例演示了 TestTransaction 的一些功能。有关 TestTransaction 的更多详细信息,请参阅 javadoc。
运行事务外部的代码
Occasionally, you may need to run certain code before or after a transactional test method but outside the transactional
context — for example, to verify the initial database state prior to running your test or to verify expected
transactional commit behavior after your test runs (if the test was configured to commit the transaction).
偶尔,您可能需要在事务性测试方法之前或之后运行某些代码,但不在事务性上下文中——例如,在运行测试之前验证初始数据库状态,或者在测试运行后验证预期的交易提交行为(如果测试被配置为提交事务)。
TransactionalTestExecutionListener supports the @BeforeTransaction and @AfterTransaction annotations for exactly
such scenarios. You can annotate any void method in a test class or any void default method in a test interface with
one of these annotations, and the TransactionalTestExecutionListener ensures that your before transaction method or
after transaction method runs at the appropriate time.
TransactionalTestExecutionListener 支持用于此类场景的 @BeforeTransaction 和 @AfterTransaction
注解。您可以使用这些注解之一来注解测试类中的任何 void 方法或测试接口中的任何 void 默认方法,
TransactionalTestExecutionListener 确保您的 before 事务方法或 after 事务方法在适当的时间运行。
Any before methods (such as methods annotated with JUnit Jupiter’s @BeforeEach) and any after methods (such as methods
annotated with JUnit Jupiter’s @AfterEach) are run within a transaction. In addition, methods annotated with
@BeforeTransaction or @AfterTransaction are not run for test methods that are not configured to run within a
transaction.
任何之前的方法(例如使用 JUnit Jupiter 的 @BeforeEach 注解的方法)和任何之后的方法(例如使用 JUnit Jupiter 的
@AfterEach 注解的方法)都在事务中运行。此外,对于未配置为在事务中运行测试方法,使用 @BeforeTransaction 或
@AfterTransaction 注解的方法不会运行。
配置事务管理器
TransactionalTestExecutionListener expects a PlatformTransactionManager bean to be defined in the Spring
ApplicationContext for the test. If there are multiple instances of PlatformTransactionManager within the test’s
ApplicationContext, you can declare a qualifier by using @Transactional("myTxMgr") or
@Transactional(transactionManager = "myTxMgr"), or TransactionManagementConfigurer can be implemented by an
@Configuration class. Consult the javadoc for
TestContextTransactionUtils.retrieveTransactionManager()
for details on the algorithm used to look up a transaction manager in the test’s ApplicationContext.
TransactionalTestExecutionListener 期望在 Spring ApplicationContext 中定义一个 PlatformTransactionManager bean
以供测试使用。如果在测试的 ApplicationContext 中存在多个 PlatformTransactionManager 实例,可以使用
@Transactional("myTxMgr") 或 @Transactional(transactionManager = "myTxMgr") 声明限定符,或者通过一个 @Configuration
类实现 TransactionManagementConfigurer 。有关在测试的 ApplicationContext 中查找事务管理器的算法详情,请参阅
TestContextTransactionUtils.retrieveTransactionManager() 的 javadoc。
演示所有交易相关标注
The following JUnit Jupiter based example displays a fictitious integration testing scenario that highlights all
transaction-related annotations. The example is not intended to demonstrate best practices but rather to demonstrate how
these annotations can be used. See the annotation support section for further
information and configuration examples. Transaction management for @Sql
contains an additional example that uses @Sql for declarative SQL script execution with default transaction rollback
semantics. The following example shows the relevant annotations:
以下基于 JUnit Jupiter 的示例展示了虚构的集成测试场景,突出了所有与事务相关的注解。此示例的目的是展示如何使用这些注解,而不是展示最佳实践。有关更多信息和管理配置示例,请参阅注解支持部分。对于
@Sql 的事务管理包含一个使用 @Sql 进行声明式 SQL 脚本执行并具有默认事务回滚语义的附加示例。以下示例显示了相关注解:
Avoid false positives when testing ORM code
避免在测试 ORM 代码时出现误报
When you test application code that manipulates the state of a Hibernate session or JPA persistence context, make sure
to flush the underlying unit of work within test methods that run that code.
当你测试操作 Hibernate 会话或 JPA 持久性上下文状态的应用程序代码时,确保在运行该代码的测试方法中刷新底层的工作单元。
Failing to flush the underlying unit of work can produce false positives: Your test passes, but the same code throws an
exception in a live, production environment. Note that this applies to any ORM framework that maintains an in-memory
unit of work.
未能刷新底层工作单元可能导致误报:您的测试通过,但相同的代码在实时、生产环境中抛出异常。请注意,这适用于任何维护内存工作单元的
ORM 框架。
In the following Hibernate-based example test case, one method demonstrates a false positive, and the other method
correctly exposes the results of flushing the session:
在以下基于 Hibernate 的示例测试用例中,一个方法演示了假阳性,另一个方法正确地暴露了刷新会话的结果:
The following example shows matching methods for JPA:
以下示例展示了 JPA 的匹配方法:
Testing ORM entity lifecycle callbacks
测试 ORM 实体生命周期回调
Similar to the note about avoiding false positives when testing ORM code, if your
application makes use of entity lifecycle callbacks (also known as entity listeners), make sure to flush the underlying
unit of work within test methods that run that code. Failing to flush or clear the underlying unit of work can
result in certain lifecycle callbacks not being invoked.
与关于测试 ORM 代码时避免假阳性的说明类似,如果你的应用程序使用了实体生命周期回调(也称为实体监听器),请确保在运行该代码的测试方法中刷新底层的单元工作。未能刷新或清除底层的单元工作可能导致某些生命周期回调未被调用。
For example, when using JPA, @PostPersist, @PreUpdate, and @PostUpdate callbacks will not be called unless
entityManager.flush() is invoked after an entity has been saved or updated. Similarly, if an entity is already
attached to the current unit of work (associated with the current persistence context), an attempt to reload the entity
will not result in a @PostLoad callback unless entityManager.clear() is invoked before the attempt to reload the
entity.
例如,在使用 JPA 时,除非在实体保存或更新后调用 entityManager.flush() ,否则 @PostPersist 、 @PreUpdate 和
@PostUpdate 回调将不会被调用。同样,如果实体已经附加到当前的工作单元(与当前持久化上下文相关联),则尝试重新加载实体不会导致
@PostLoad 回调,除非在尝试重新加载实体之前调用 entityManager.clear() 。
The following example shows how to flush the EntityManager to ensure that @PostPersist callbacks are invoked when an
entity is persisted. An entity listener with a @PostPersist callback method has been registered for the Person
entity used in the example.
以下示例展示了如何刷新 EntityManager 以确保在实体持久化时调用 @PostPersist 回调。已为示例中使用的 Person 实体注册了一个具有
@PostPersist 回调方法的实体监听器。
See JpaEntityListenerTests
in the Spring Framework test suite for working examples using all JPA lifecycle callbacks.
查看 Spring 框架测试套件中的 JpaEntityListenerTests 以获取使用所有 JPA 生命周期回调的工作示例。
3.5.10. 执行 SQL 脚本
When writing integration tests against a relational database, it is often beneficial to run SQL scripts to modify the
database schema or insert test data into tables. The spring-jdbc module provides support for initializing an
embedded or existing database by executing SQL scripts when the Spring ApplicationContext is loaded.
See Embedded database support
and Testing data access logic with an embedded database
for details.
在编写针对关系型数据库的集成测试时,运行 SQL 脚本以修改数据库模式或向表中插入测试数据通常是有益的。 spring-jdbc 模块提供在
Spring ApplicationContext 加载时通过执行 SQL 脚本初始化嵌入式或现有数据库的支持。有关嵌入式数据库支持和使用嵌入式数据库测试数据访问逻辑的详细信息,请参阅。
Although it is very useful to initialize a database for testing once when the ApplicationContext is loaded,
sometimes it is essential to be able to modify the database during integration tests. The following sections explain
how to run SQL scripts programmatically and declaratively during integration tests.
尽管在加载 ApplicationContext 时初始化数据库对测试非常有用,但在集成测试中有时修改数据库是必不可少的。以下章节将解释如何在集成测试中程序化和声明式地运行
SQL 脚本。
执行 SQL 脚本程序化
Spring provides the following options for executing SQL scripts programmatically within integration test methods.
Spring 为在集成测试方法中程序化执行 SQL 脚本提供了以下选项。
org.springframework.jdbc.datasource.init.ScriptUtils
org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests
org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests
ScriptUtils provides a collection of static utility methods for working with SQL scripts and is mainly intended for
internal use within the framework. However, if you require full control over how SQL scripts are parsed and run,
ScriptUtils may suit your needs better than some of the other alternatives described later. See
the javadoc
for individual methods in ScriptUtils for further details.
ScriptUtils 提供了一组用于处理 SQL 脚本的静态实用方法,主要用于框架内部的内部使用。然而,如果您需要完全控制 SQL
脚本的解析和运行方式, ScriptUtils 可能比后面描述的其他一些替代方案更适合您的需求。有关 ScriptUtils 中各个方法的详细信息,请参阅
javadoc。
ResourceDatabasePopulator provides an object-based API for programmatically populating, initializing, or cleaning up a
database by using SQL scripts defined in external resources. ResourceDatabasePopulator provides options for
configuring the character encoding, statement separator, comment delimiters, and error handling flags used when parsing
and running the scripts. Each of the configuration options has a reasonable default value. See
the javadoc
for details on default values. To run the scripts configured in a ResourceDatabasePopulator, you can invoke either the
populate(Connection) method to run the populator against a java.sql.Connection or the execute(DataSource) method
to run the populator against a javax.sql.DataSource. The following example specifies SQL scripts for a test schema and
test data, sets the statement separator to @@, and run the scripts against a DataSource:
ResourceDatabasePopulator 提供了一个基于对象的 API,通过使用外部资源中定义的 SQL 脚本,以编程方式填充、初始化或清理数据库。
ResourceDatabasePopulator 提供了配置字符编码、语句分隔符、注释定界符和错误处理标志的选项,这些选项在解析和运行脚本时使用。每个配置选项都有一个合理的默认值。有关默认值详情,请参阅
javadoc。要运行配置在 ResourceDatabasePopulator 中的脚本,您可以调用 populate(Connection) 方法来运行填充器针对
java.sql.Connection 执行,或者调用 execute(DataSource) 方法来运行填充器针对 javax.sql.DataSource
执行。以下示例指定了测试模式和测试数据的 SQL 脚本,将语句分隔符设置为 @@ ,并在 DataSource 上运行脚本:
Note that ResourceDatabasePopulator internally delegates to ScriptUtils for parsing and running SQL scripts.
Similarly, the executeSqlScript(..) methods in
AbstractTransactionalJUnit4SpringContextTests and
AbstractTransactionalTestNGSpringContextTests internally use a
ResourceDatabasePopulator to run SQL scripts. See the Javadoc for the various executeSqlScript(..) methods for
further details.
请注意, ResourceDatabasePopulator 在内部委托给 ScriptUtils 进行解析和运行 SQL 脚本。同样,
AbstractTransactionalJUnit4SpringContextTests 和 AbstractTransactionalTestNGSpringContextTests 中的
executeSqlScript(..) 方法在内部使用 ResourceDatabasePopulator 运行 SQL 脚本。有关各种 executeSqlScript(..)
方法的详细信息,请参阅 Javadoc。
执行 SQL 脚本声明式地使用@Sql
In addition to the aforementioned mechanisms for running SQL scripts programmatically, you can declaratively configure
SQL scripts in the Spring TestContext Framework. Specifically, you can declare the @Sql annotation on a test class or
test method to configure individual SQL statements or the resource paths to SQL scripts that should be run against a
given database before or after an integration test method. Support for @Sql is provided by the
SqlScriptsTestExecutionListener, which is enabled by default.
除了上述用于程序化运行 SQL 脚本的机制之外,您还可以在 Spring TestContext 框架中以声明方式配置 SQL 脚本。具体来说,您可以在测试类或测试方法上声明
@Sql 注解来配置单个 SQL 语句或应在给定数据库上运行之前或之后执行的 SQL 脚本资源路径。 @Sql 的支持由
SqlScriptsTestExecutionListener 提供,默认情况下已启用。
Method-level @Sql declarations override class-level declarations by default. As of Spring Framework 5.2, however, this
behavior may be configured per test class or per test method via @SqlMergeMode.
See Merging and Overriding Configuration with @SqlMergeMode
for further details.
方法级别的 @Sql 声明默认会覆盖类级别的声明。然而,从 Spring Framework 5.2 开始,可以通过 @SqlMergeMode
分别针对测试类或测试方法进行配置。有关使用 @SqlMergeMode 合并和覆盖配置的详细信息,请参阅相关内容。
Each path is interpreted as a Spring Resource. A plain path (for example, "schema.sql") is treated as a classpath
resource that is relative to the package in which the test class is defined. A path starting with a slash is treated as
an absolute classpath resource (for example, "/org/example/schema.sql"). A path that references a URL (for example, a
path prefixed with classpath:, file:, http:) is loaded by using the specified resource protocol.
每个路径被解释为 Spring Resource 。一个普通路径(例如, "schema.sql" )被视为相对于定义测试类的包的类路径资源。以斜杠开头的路径被视为绝对类路径资源(例如,
"/org/example/schema.sql" )。引用 URL 的路径(例如,以 classpath: 、 file: 、 http: 为前缀的路径)通过指定的资源协议进行加载。
The following example shows how to use @Sql at the class level and at the method level within a JUnit Jupiter based
integration test class:
以下示例展示了如何在 JUnit Jupiter 基于的集成测试类中,在类级别和方法级别使用 @Sql
默认脚本检测
If no SQL scripts or statements are specified, an attempt is made to detect a default script, depending on where
@Sql is declared. If a default cannot be detected, an IllegalStateException is thrown.
如果没有指定 SQL 脚本或语句,将尝试检测一个 default 脚本,具体取决于 @Sql 在哪里声明。如果无法检测到默认值,将抛出
IllegalStateException 。
Class-level declaration: If the annotated test class is com.example.MyTest, the corresponding default script is
classpath:com/example/MyTest.sql.
类级别声明:如果注解的测试类是 com.example.MyTest ,则相应的默认脚本为 classpath:com/example/MyTest.sql 。
Method-level declaration: If the annotated test method is named testMethod() and is defined in the class
com.example.MyTest, the corresponding default script is classpath:com/example/MyTest.testMethod.sql.
方法级声明:如果注解的测试方法名为 testMethod() ,且定义在类 com.example.MyTest 中,则相应的默认脚本为
classpath:com/example/MyTest.testMethod.sql 。
@Sql Sets声明多个 @Sql 集合
If you need to configure multiple sets of SQL scripts for a given test class or test method but with different syntax
configuration, different error handling rules, or different execution phases per set, you can declare multiple instances
of @Sql. With Java 8, you can use @Sql as a repeatable annotation. Otherwise, you can use the @SqlGroup annotation
as an explicit container for declaring multiple instances of @Sql.
如果您需要为特定的测试类或测试方法配置多套具有不同语法配置、不同错误处理规则或每套不同的执行阶段的 SQL 脚本,您可以声明多个
@Sql 实例。在 Java 8 中,您可以使用 @Sql 作为可重复的注解。否则,您可以使用 @SqlGroup 注解作为显式容器来声明多个
@Sql 实例。
The following example shows how to use @Sql as a repeatable annotation with Java 8:
以下示例展示了如何使用 @Sql 作为 Java 8 的可重复注解:
In the scenario presented in the preceding example, the test-schema.sql script uses a different syntax for single-line
comments.
在前面示例中提出的场景中, test-schema.sql 脚本使用不同的语法来表示单行注释。
The following example is identical to the preceding example, except that the @Sql declarations are grouped together
within @SqlGroup. With Java 8 and above, the use of @SqlGroup is optional, but you may need to use @SqlGroup for
compatibility with other JVM languages such as Kotlin.
以下示例与前面的示例相同,除了 @Sql 声明被组合在一起在 @SqlGroup 中。在 Java 8 及以上版本中,使用 @SqlGroup
是可选的,但为了与其他 JVM 语言(如 Kotlin)兼容,可能需要使用 @SqlGroup 。
By default, SQL scripts are run before the corresponding test method. However, if you need to run a particular set of
scripts after the test method (for example, to clean up database state), you can use the executionPhase attribute in
@Sql, as the following example shows:
默认情况下,SQL 脚本在相应的测试方法之前运行。然而,如果您需要在测试方法之后运行特定的脚本集(例如,为了清理数据库状态),您可以在
@Sql 中使用 executionPhase 属性,如下例所示:
Note that ISOLATED and AFTER_TEST_METHOD are statically imported from Sql.TransactionMode and
Sql.ExecutionPhase, respectively.
请注意, ISOLATED 和 AFTER_TEST_METHOD 分别从 Sql.TransactionMode 和 Sql.ExecutionPhase 静态导入。
@SqlConfig脚本配置与 @SqlConfig
You can configure script parsing and error handling by using the @SqlConfig annotation. When declared as a class-level
annotation on an integration test class, @SqlConfig serves as global configuration for all SQL scripts within the test
class hierarchy. When declared directly by using the config attribute of the @Sql annotation, @SqlConfig serves as
local configuration for the SQL scripts declared within the enclosing @Sql annotation. Every attribute in @SqlConfig
has an implicit default value, which is documented in the javadoc of the corresponding attribute. Due to the rules
defined for annotation attributes in the Java Language Specification, it is, unfortunately, not possible to assign a
value of null to an annotation attribute. Thus, in order to support overrides of inherited global configuration,
@SqlConfig attributes have an explicit default value of either "" (for Strings), {} (for arrays), or DEFAULT (
for enumerations). This approach lets local declarations of @SqlConfig selectively override individual attributes from
global declarations of @SqlConfig by providing a value other than "", {}, or DEFAULT. Global @SqlConfig
attributes are inherited whenever local @SqlConfig attributes do not supply an explicit value other than "", {},
or DEFAULT. Explicit local configuration, therefore, overrides global configuration.
您可以通过使用 @SqlConfig 注解来配置脚本解析和错误处理。当作为集成测试类的类级别注解声明时, @SqlConfig 为测试类层次结构中的所有
SQL 脚本提供全局配置。当直接使用 @Sql 注解的 config 属性声明时, @SqlConfig 作为包含在 @Sql 注解内的 SQL 脚本的局部配置。
@SqlConfig 中的每个属性都有一个隐式的默认值,这在相应属性的 javadoc 中有文档说明。由于 Java 语言规范中定义的注解属性规则,不幸的是,无法将
null 的值分配给注解属性。因此,为了支持继承的全局配置的重写, @SqlConfig 属性具有显式的默认值,可以是 "" (对于字符串)、
{} (对于数组)或 DEFAULT (对于枚举)。这种方法允许局部声明 @SqlConfig 通过提供除 "" 、 {} 或 DEFAULT
之外的其他值,有选择地覆盖全局声明 @SqlConfig 中的单个属性。 全局 @SqlConfig 属性在本地 @SqlConfig 属性未提供除
"" 、 {} 或 DEFAULT 之外的其他显式值时会被继承。因此,显式本地配置会覆盖全局配置。
The configuration options provided by @Sql and @SqlConfig are equivalent to those supported by ScriptUtils and
ResourceDatabasePopulator but are a superset of those provided by the <jdbc:initialize-database/> XML namespace
element. See the javadoc of individual attributes in
@Sql
and
@SqlConfig
for details.
提供的 @Sql 和 @SqlConfig 配置选项等同于 ScriptUtils 和 ResourceDatabasePopulator 支持的选项,但它们是
<jdbc:initialize-database/> XML 命名空间元素提供的选项的超集。有关各个属性的详细信息,请参阅 @Sql 和 @SqlConfig 的
javadoc。
Transaction management for @Sql
交易管理 for @Sql
By default, the SqlScriptsTestExecutionListener infers the desired transaction semantics for scripts configured by
using @Sql. Specifically, SQL scripts are run without a transaction, within an existing Spring-managed transaction (
for example, a transaction managed by the TransactionalTestExecutionListener for a test annotated with
@Transactional), or within an isolated transaction, depending on the configured value of the transactionMode
attribute in @SqlConfig and the presence of a PlatformTransactionManager in the test’s ApplicationContext. As a
bare minimum, however, a javax.sql.DataSource must be present in the test’s ApplicationContext.
默认情况下, SqlScriptsTestExecutionListener 推断由 @Sql 配置的脚本所期望的事务语义。具体来说,SQL 脚本在没有事务的情况下运行,在现有的
Spring 管理的事务内(例如,由 TransactionalTestExecutionListener 管理的事务,对于一个带有 @Transactional
注解的测试),或者在一个隔离的事务内,这取决于 @SqlConfig 中 transactionMode 属性的配置值以及测试的
ApplicationContext 中是否存在 PlatformTransactionManager 。然而,至少在测试的 ApplicationContext 中必须存在一个
javax.sql.DataSource 。
If the algorithms used by SqlScriptsTestExecutionListener to detect a DataSource and PlatformTransactionManager
and infer the transaction semantics do not suit your needs, you can specify explicit names by setting the dataSource
and transactionManager attributes of @SqlConfig. Furthermore, you can control the transaction propagation behavior
by setting the transactionMode attribute of @SqlConfig (for example, whether scripts should be run in an isolated
transaction). Although a thorough discussion of all supported options for transaction management with @Sql is beyond
the scope of this reference manual, the javadoc for
@SqlConfig
and
SqlScriptsTestExecutionListener
provide detailed information, and the following example shows a typical testing scenario that uses JUnit Jupiter and
transactional tests with @Sql:
如果 SqlScriptsTestExecutionListener 用于检测 DataSource 和 PlatformTransactionManager 以及推断事务语义的算法不符合您的需求,您可以通过设置
@SqlConfig 的 dataSource 和 transactionManager 属性来指定显式名称。此外,您可以通过设置 @SqlConfig 的
transactionMode 属性来控制事务传播行为(例如,脚本是否应在隔离事务中运行)。尽管对所有支持的事务管理选项的详细讨论超出了本参考手册的范围,但
@SqlConfig 和 SqlScriptsTestExecutionListener 的 javadoc 提供了详细信息,以下示例展示了使用 JUnit Jupiter 和带有
@Sql 的事务测试的典型测试场景:
Note that there is no need to clean up the database after the usersTest() method is run, since any changes made to the
database (either within the test method or within the /test-data.sql script) are automatically rolled back by the
TransactionalTestExecutionListener (see transaction management for details).
注意,在运行 usersTest() 方法后无需清理数据库,因为对数据库的任何更改(无论是测试方法内部还是 /test-data.sql 脚本内部)都会被
TransactionalTestExecutionListener 自动回滚(有关事务管理详情请参阅)。
@SqlMergeMode合并和覆盖配置与 @SqlMergeMode
As of Spring Framework 5.2, it is possible to merge method-level @Sql declarations with class-level declarations. For
example, this allows you to provide the configuration for a database schema or some common test data once per test class
and then provide additional, use case specific test data per test method. To enable @Sql merging, annotate either your
test class or test method with @SqlMergeMode(MERGE). To disable merging for a specific test method (or specific test
subclass), you can switch back to the default mode via @SqlMergeMode(OVERRIDE). Consult the
@SqlMergeMode annotation documentation section for examples and further
details.
截至 Spring Framework 5.2,可以将方法级别的 @Sql
声明与类级别的声明合并。例如,这允许您在每个测试类中一次提供数据库模式或一些常见测试数据的配置,然后为每个测试方法提供额外的、特定于用例的测试数据。要启用
@Sql 合并,请使用 @SqlMergeMode(MERGE) 注解您的测试类或测试方法。要为特定的测试方法(或特定的测试子类)禁用合并,可以通过
@SqlMergeMode(OVERRIDE) 切换回默认模式。请参阅 @SqlMergeMode 注解文档部分以获取示例和更多详细信息。
3.5.11. 并行测试执行
Spring Framework 5.0 introduced basic support for executing tests in parallel within a single JVM when using the Spring
TestContext Framework. In general, this means that most test classes or test methods can be run in parallel without any
changes to test code or configuration.
Spring Framework 5.0 在使用 Spring TestContext 框架时引入了对单个 JVM
内并行执行测试的基本支持。一般来说,这意味着大多数测试类或测试方法可以并行运行,而无需修改测试代码或配置。
For details on how to set up parallel test execution, see the documentation for your testing framework, build tool, or
IDE.
有关如何设置并行测试执行的详细信息,请参阅您的测试框架、构建工具或 IDE 的文档。
Keep in mind that the introduction of concurrency into your test suite can result in unexpected side effects, strange
runtime behavior, and tests that fail intermittently or seemingly randomly.
请注意,将并发引入您的测试套件可能会导致意外的副作用、奇怪的运行时行为,以及间歇性或看似随机失败的测试。
The Spring Team therefore provides the following general guidelines for when not to run tests in parallel.
春季团队因此提供了以下一般性指南,说明何时不应并行运行测试。
Do not run tests in parallel if the tests:
不要并行运行测试,如果测试:
Use Spring Framework’s @DirtiesContext support.
使用 Spring 框架的 @DirtiesContext 支持。
Use Spring Boot’s @MockBean or @SpyBean support.
使用 Spring Boot 的 @MockBean 或 @SpyBean 支持。
Use JUnit 4’s @FixMethodOrder support or any testing framework feature that is designed to ensure that test methods
run in a particular order. Note, however, that this does not apply if entire test classes are run in parallel.
使用 JUnit 4 的 @FixMethodOrder 支持或任何旨在确保测试方法按特定顺序运行的测试框架功能。请注意,然而,如果整个测试类并行运行,则此规则不适用。
Change the state of shared services or systems such as a database, message broker, filesystem, and others. This
applies to both embedded and external systems.
更改共享服务或系统(如数据库、消息代理、文件系统等)的状态。这适用于嵌入式和外部系统。
If parallel test execution fails with an exception stating that the ApplicationContext for the current test is no
longer active, this typically means that the ApplicationContext was removed from the ContextCache in a different
thread.
如果并行测试执行失败,并抛出异常指出当前测试的 ApplicationContext 已不再活跃,这通常意味着 ApplicationContext
在另一个线程中被从 ContextCache 中移除。
This may be due to the use of @DirtiesContext or due to automatic eviction from the ContextCache. If
@DirtiesContext is the culprit, you either need to find a way to avoid using @DirtiesContext or exclude such tests
from parallel execution. If the maximum size of the ContextCache has been exceeded, you can increase the maximum size
of the cache. See the discussion on context caching for details.
这可能是由于使用了 @DirtiesContext ,或者是由于自动从 ContextCache 中移除。如果 @DirtiesContext 是罪魁祸首,您要么需要找到一种避免使用
@DirtiesContext 的方法,要么将此类测试从并行执行中排除。如果 ContextCache 的最大大小已超过,您可以增加缓存的最大大小。有关上下文缓存的讨论,请参阅详细信息。
Parallel test execution in the Spring TestContext Framework is only possible if the underlying TestContext
implementation provides a copy constructor, as explained in the javadoc for
TestContext.
The DefaultTestContext used in Spring provides such a constructor. However, if you use a third-party library that
provides a custom TestContext implementation, you need to verify that it is suitable for parallel test execution.
并行测试执行在 Spring TestContext 框架中仅当底层实现提供复制构造函数时才可能,如 TestContext 的 javadoc 中所述。Spring
中使用的 DefaultTestContext 提供了这样的构造函数。然而,如果您使用提供自定义 TestContext 实现的第三方库,您需要验证它是否适合并行测试执行。
3.5.12. 测试上下文框架支持类
This section describes the various classes that support the Spring TestContext Framework.
本节描述了支持 Spring TestContext 框架的各种类。
Spring JUnit 4 Runner:Spring JUnit 4 运行器
The Spring TestContext Framework offers full integration with JUnit 4 through a custom runner (supported on JUnit 4.12
or higher). By annotating test classes with @RunWith(SpringJUnit4ClassRunner.class) or the shorter
@RunWith(SpringRunner.class) variant, developers can implement standard JUnit 4-based unit and integration tests and
simultaneously reap the benefits of the TestContext framework, such as support for loading application contexts,
dependency injection of test instances, transactional test method execution, and so on.
Spring TestContext 框架通过自定义运行器(支持 JUnit 4.12 或更高版本)与 JUnit 4 实现了完全集成。通过使用
@RunWith(SpringJUnit4ClassRunner.class) 或更简短的 @RunWith(SpringRunner.class) 变体注解测试类,开发者可以实现基于
JUnit 4 的标准单元和集成测试,并同时获得 TestContext
框架的好处,例如支持加载应用程序上下文、测试实例的依赖注入、事务性测试方法执行等。
If you want to use the Spring TestContext Framework with an alternative runner (such as JUnit 4’s Parameterized
runner) or third-party runners (such as the MockitoJUnitRunner), you can, optionally,
use Spring’s support for JUnit rules instead.
如果您想使用 Spring TestContext 框架与替代运行器(如 JUnit 4 的 Parameterized 运行器)或第三方运行器(如
MockitoJUnitRunner ),您可以选择使用 Spring 对 JUnit 规则的支持。
The following code listing shows the minimal requirements for configuring a test class to run with the custom Spring
Runner:
以下代码列表显示了配置测试类以使用自定义 Spring Runner 运行的最小要求
In the preceding example, @TestExecutionListeners is configured with an empty list, to disable the default listeners,
which otherwise would require an ApplicationContext to be configured through @ContextConfiguration.
在先前的示例中, @TestExecutionListeners 配置为空列表,以禁用默认监听器,否则将需要通过 @ContextConfiguration 配置
ApplicationContext 。
Spring JUnit 4 规则
The org.springframework.test.context.junit4.rules package provides the following JUnit 4 rules (supported on JUnit
4.12 or higher):
The org.springframework.test.context.junit4.rules package provides the following JUnit 4 rules (supported on JUnit
4.12 or higher): 该 org.springframework.test.context.junit4.rules 包提供以下 JUnit 4 规则(支持 JUnit 4.12 或更高版本):
SpringClassRule
SpringMethodRule
SpringClassRule is a JUnit TestRule that supports class-level features of the Spring TestContext Framework, whereas
SpringMethodRule is a JUnit MethodRule that supports instance-level and method-level features of the Spring
TestContext Framework.
SpringClassRule 是支持 Spring TestContext 框架类级别功能的 JUnit TestRule ,而 SpringMethodRule 是支持 Spring
TestContext 框架实例级别和方法级别功能的 JUnit MethodRule 。
In contrast to the SpringRunner, Spring’s rule-based JUnit support has the advantage of being independent of any
org.junit.runner.Runner implementation and can, therefore, be combined with existing alternative runners (such as
JUnit 4’s Parameterized) or third-party runners (such as the MockitoJUnitRunner).
与 SpringRunner 相比,Spring 的基于规则的 JUnit 支持具有独立于任何 org.junit.runner.Runner 实现的优势,因此可以与现有的替代运行器(如
JUnit 4 的 Parameterized )或第三方运行器(如 MockitoJUnitRunner )结合使用。
To support the full functionality of the TestContext framework, you must combine a SpringClassRule with a
SpringMethodRule. The following example shows the proper way to declare these rules in an integration test:
为了支持 TestContext 框架的完整功能,您必须结合一个 SpringClassRule 和一个 SpringMethodRule
。以下示例展示了在集成测试中正确声明这些规则的方法:
JUnit 4 支持类
The org.springframework.test.context.junit4 package provides the following support classes for JUnit 4-based test
cases (supported on JUnit 4.12 or higher):
The org.springframework.test.context.junit4 包为基于 JUnit 4 的测试用例提供以下支持类(支持 JUnit 4.12 或更高版本):
AbstractJUnit4SpringContextTests
AbstractTransactionalJUnit4SpringContextTests
AbstractJUnit4SpringContextTests is an abstract base test class that integrates the Spring TestContext Framework with
explicit ApplicationContext testing support in a JUnit 4 environment. When you extend
AbstractJUnit4SpringContextTests, you can access a protected applicationContext instance variable that you can use
to perform explicit bean lookups or to test the state of the context as a whole.
AbstractJUnit4SpringContextTests 是一个抽象基测试类,它将 Spring TestContext 框架与 JUnit 4 环境中的显式
ApplicationContext 测试支持集成。当你扩展 AbstractJUnit4SpringContextTests 时,你可以访问一个 protected
applicationContext 实例变量,你可以使用它来执行显式的 Bean 查找或测试上下文的整体状态。
AbstractTransactionalJUnit4SpringContextTests is an abstract transactional extension of
AbstractJUnit4SpringContextTests that adds some convenience functionality for JDBC access. This class expects a
javax.sql.DataSource bean and a PlatformTransactionManager bean to be defined in the ApplicationContext. When you
extend AbstractTransactionalJUnit4SpringContextTests, you can access a protected jdbcTemplate instance variable
that you can use to run SQL statements to query the database.
AbstractTransactionalJUnit4SpringContextTests 是 AbstractJUnit4SpringContextTests 的一个抽象事务扩展,为 JDBC
访问添加了一些便利功能。此类期望在 ApplicationContext 中定义一个 javax.sql.DataSource 实例和一个
PlatformTransactionManager 实例。当你扩展 AbstractTransactionalJUnit4SpringContextTests 时,你可以访问一个 protected
jdbcTemplate 实例变量,你可以使用它来运行 SQL 语句以查询数据库。
You can use such queries to confirm database state both before and after running database-related application code, and
Spring ensures that such queries run in the scope of the same transaction as the application code. When used in
conjunction with an ORM tool, be sure to avoid false positives. As mentioned
in JDBC Testing Support, AbstractTransactionalJUnit4SpringContextTests also
provides convenience methods that delegate to methods in JdbcTestUtils by using the aforementioned jdbcTemplate.
Furthermore, AbstractTransactionalJUnit4SpringContextTests provides an executeSqlScript(..) method for running SQL
scripts against the configured DataSource.
您可以使用此类查询来确认在运行数据库相关应用程序代码之前和之后数据库的状态,Spring 确保此类查询在与应用程序代码相同的事务范围内运行。当与
ORM 工具结合使用时,请确保避免误报。如 JDBC 测试支持中所述, AbstractTransactionalJUnit4SpringContextTests 还提供了通过使用上述
jdbcTemplate 委派给 JdbcTestUtils 中方法的便利方法。此外, AbstractTransactionalJUnit4SpringContextTests 提供了一个针对配置的
DataSource 运行 SQL 脚本的 executeSqlScript(..) 方法。
These classes are a convenience for extension. If you do not want your test classes to be tied to a Spring-specific
class hierarchy, you can configure your own custom test classes by using @RunWith(SpringRunner.class)
or Spring’s JUnit rules.
这些类是为了扩展而提供的便利。如果您不希望您的测试类与 Spring 特定的类层次结构绑定,您可以通过使用
@RunWith(SpringRunner.class) 或 Spring 的 JUnit 规则来配置自己的自定义测试类。
SpringExtension for JUnit Jupiter SpringExtension for JUnit Jupiter
The Spring TestContext Framework offers full integration with the JUnit Jupiter testing framework, introduced in JUnit
5. By annotating test classes with @ExtendWith(SpringExtension.class), you can implement standard JUnit Jupiter-based
unit and integration tests and simultaneously reap the benefits of the TestContext framework, such as support for
loading application contexts, dependency injection of test instances, transactional test method execution, and so on.
Spring TestContext 框架与 JUnit Jupiter 测试框架(在 JUnit 5 中引入)提供全面集成。通过使用
@ExtendWith(SpringExtension.class) 注解测试类,您可以实现基于 JUnit Jupiter 的标准单元和集成测试,并同时享受 TestContext
框架带来的好处,例如支持加载应用程序上下文、测试实例的依赖注入、事务性测试方法执行等。
Furthermore, thanks to the rich extension API in JUnit Jupiter, Spring provides the following features above and beyond
the feature set that Spring supports for JUnit 4 and TestNG:
此外,得益于 JUnit Jupiter 丰富的扩展 API,Spring 提供了以下超出 Spring 对 JUnit 4 和 TestNG 支持的功能集:
Dependency injection for test constructors, test methods, and test lifecycle callback methods.
See Dependency Injection with SpringExtension for further details.
依赖注入用于测试构造函数、测试方法和测试生命周期回调方法。有关详细信息,请参阅 SpringExtension 中的依赖注入。
Powerful support
for conditional test execution based on
SpEL expressions, environment variables, system properties, and so on. See the documentation for @EnabledIf and
@DisabledIf in Spring JUnit Jupiter Testing Annotations for
further details and examples.
强大的基于 SpEL 表达式、环境变量、系统属性等的条件测试执行支持。请参阅 Spring JUnit Jupiter 测试注解中 @EnabledIf 和
@DisabledIf 的文档以获取更多详细信息及示例。
Custom composed annotations that combine annotations from Spring and JUnit Jupiter. See the
@TransactionalDevTestConfig and @TransactionalIntegrationTest examples
in Meta-Annotation Support for Testing for further details.
自定义组合 Spring 和 JUnit Jupiter 的注解。请参阅测试元注解支持中的 @TransactionalDevTestConfig 和
@TransactionalIntegrationTest 示例以获取更多详细信息。
The following code listing shows how to configure a test class to use the SpringExtension in conjunction with
@ContextConfiguration:
以下代码列表展示了如何配置测试类以使用 SpringExtension 结合 @ContextConfiguration :
Since you can also use annotations in JUnit 5 as meta-annotations, Spring provides the @SpringJUnitConfig and
@SpringJUnitWebConfig composed annotations to simplify the configuration of the test ApplicationContext and JUnit
Jupiter.
由于您也可以在 JUnit 5 中使用注解作为元注解,Spring 提供了 @SpringJUnitConfig 和 @SpringJUnitWebConfig 组合注解来简化测试
ApplicationContext 和 JUnit Jupiter 的配置。
The following example uses @SpringJUnitConfig to reduce the amount of configuration used in the previous example:
以下示例使用 @SpringJUnitConfig 来减少之前示例中使用的配置量:
Similarly, the following example uses @SpringJUnitWebConfig to create a WebApplicationContext for use with JUnit
Jupiter:
同样,以下示例使用 @SpringJUnitWebConfig 创建一个用于与 JUnit Jupiter 一起使用的 WebApplicationContext :
See the documentation for @SpringJUnitConfig and @SpringJUnitWebConfig
in Spring JUnit Jupiter Testing Annotations for further details.
查看 Spring JUnit Jupiter 测试注解中 @SpringJUnitConfig 和 @SpringJUnitWebConfig 的文档以获取更多详细信息。
SpringExtension依赖注入与 SpringExtension
SpringExtension implements the
ParameterResolver extension API
from JUnit Jupiter, which lets Spring provide dependency injection for test constructors, test methods, and test
lifecycle callback methods.
SpringExtension 实现了 JUnit Jupiter 的 ParameterResolver 扩展 API,这使得 Spring 可以为测试构造函数、测试方法和测试生命周期回调方法提供依赖注入。
Specifically, SpringExtension can inject dependencies from the test’s ApplicationContext into test constructors and
methods that are annotated with @BeforeAll, @AfterAll, @BeforeEach, @AfterEach, @Test, @RepeatedTest,
@ParameterizedTest, and others.
具体来说, SpringExtension 可以将测试的 ApplicationContext 注入到带有 @BeforeAll 、 @AfterAll 、 @BeforeEach 、
@AfterEach 、 @Test 、 @RepeatedTest 、 @ParameterizedTest 等注解的测试构造函数和方法中。
If a specific parameter in a constructor for a JUnit Jupiter test class is of type ApplicationContext (or a sub-type
thereof) or is annotated or meta-annotated with @Autowired, @Qualifier, or @Value, Spring injects the value for
that specific parameter with the corresponding bean or value from the test’s ApplicationContext.
如果一个 JUnit Jupiter 测试类的构造函数中的特定参数是类型 ApplicationContext (或其子类型)或者被注解或元注解为
@Autowired , @Qualifier ,或 @Value ,Spring 将使用测试的 ApplicationContext 中对应的 bean 或值来注入该特定参数的值。
Spring can also be configured to autowire all arguments for a test class constructor if the constructor is considered to
be autowirable. A constructor is considered to be autowirable if one of the following conditions is met (in order of
precedence).
春季还可以配置自动注入测试类构造函数的所有参数,如果构造函数被认为是可自动装配的。当满足以下条件之一(按优先级顺序)时,构造函数被认为是可自动装配的。
The constructor is annotated with @Autowired.
@TestConstructor is present or meta-present on the test class with the autowireMode attribute set to ALL.
The default test constructor autowire mode has been changed to ALL.
See @TestConstructor for details on the use of @TestConstructor
and how to change the global test constructor autowire mode.
If the constructor for a test class is considered to be autowirable, Spring assumes the responsibility for resolving
arguments for all parameters in the constructor. Consequently, no other ParameterResolver registered with JUnit
Jupiter can resolve parameters for such a constructor.
Constructor injection for test classes must not be used in conjunction with JUnit Jupiter’s @TestInstance(PER_CLASS)
support if @DirtiesContext is used to close the test’s ApplicationContext before or after test methods.
The reason is that @TestInstance(PER_CLASS) instructs JUnit Jupiter to cache the test instance between test method
invocations. Consequently, the test instance will retain references to beans that were originally injected from an
ApplicationContext that has been subsequently closed. Since the constructor for the test class will only be invoked
once in such scenarios, dependency injection will not occur again, and subsequent tests will interact with beans from
the closed ApplicationContext which may result in errors.
To use @DirtiesContext with "before test method" or "after test method" modes in conjunction with
@TestInstance(PER_CLASS), one must configure dependencies from Spring to be supplied via field or setter injection so
that they can be re-injected between test method invocations.
In the following example, Spring injects the OrderService bean from the ApplicationContext loaded from
TestConfig.class into the OrderServiceIntegrationTests constructor.
Note that this feature lets test dependencies be final and therefore immutable.
If the spring.test.constructor.autowire.mode property is to all (see
@TestConstructor), we can omit the declaration of @Autowired on
the constructor in the previous example, resulting in the following.
If a parameter in a JUnit Jupiter test method or test lifecycle callback method is of type ApplicationContext (or a
sub-type thereof) or is annotated or meta-annotated with @Autowired, @Qualifier, or @Value, Spring injects the
value for that specific parameter with the corresponding bean from the test’s ApplicationContext.
In the following example, Spring injects the OrderService from the ApplicationContext loaded from TestConfig.class
into the deleteOrder() test method:
Due to the robustness of the ParameterResolver support in JUnit Jupiter, you can also have multiple dependencies
injected into a single method, not only from Spring but also from JUnit Jupiter itself or other third-party extensions.
The following example shows how to have both Spring and JUnit Jupiter inject dependencies into the
placeOrderRepeatedly() test method simultaneously.
Note that the use of @RepeatedTest from JUnit Jupiter lets the test method gain access to the RepetitionInfo.
@Nested test class configurationThe Spring TestContext Framework has supported the use of test-related annotations on @Nested test classes in JUnit
Jupiter since Spring Framework 5.0; however, until Spring Framework 5.3 class-level test configuration annotations were
not inherited from enclosing classes like they are from superclasses.
Spring Framework 5.3 introduces first-class support for inheriting test class configuration from enclosing classes, and
such configuration will be inherited by default. To change from the default INHERIT mode to OVERRIDE mode, you may
annotate an individual @Nested test class with @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE). An
explicit @NestedTestConfiguration declaration will apply to the annotated test class as well as any of its subclasses
and nested classes. Thus, you may annotate a top-level test class with @NestedTestConfiguration, and that will apply
to all of its nested test classes recursively.
In order to allow development teams to change the default to OVERRIDE – for example, for compatibility with Spring
Framework 5.0 through 5.2 – the default mode can be changed globally via a JVM system property or a spring.properties
file in the root of the classpath. See
the "Changing the default enclosing configuration inheritance mode"
note for details.
Although the following "Hello World" example is very simplistic, it shows how to declare common configuration on a
top-level class that is inherited by its @Nested test classes. In this particular example, only the TestConfig
configuration class is inherited. Each nested test class provides its own set of active profiles, resulting in a
distinct ApplicationContext for each nested test class (see Context Caching for
details). Consult the list of supported annotations to see
which annotations can be inherited in @Nested test classes.
The org.springframework.test.context.testng package provides the following support classes for TestNG based test
cases:
AbstractTestNGSpringContextTests
AbstractTransactionalTestNGSpringContextTests
AbstractTestNGSpringContextTests is an abstract base test class that integrates the Spring TestContext Framework with
explicit ApplicationContext testing support in a TestNG environment. When you extend
AbstractTestNGSpringContextTests, you can access a protected applicationContext instance variable that you can use
to perform explicit bean lookups or to test the state of the context as a whole.
AbstractTransactionalTestNGSpringContextTests is an abstract transactional extension of
AbstractTestNGSpringContextTests that adds some convenience functionality for JDBC access. This class expects a
javax.sql.DataSource bean and a PlatformTransactionManager bean to be defined in the ApplicationContext. When you
extend AbstractTransactionalTestNGSpringContextTests, you can access a protected jdbcTemplate instance variable
that you can use to run SQL statements to query the database. You can use such queries to confirm database state both
before and after running database-related application code, and Spring ensures that such queries run in the scope of the
same transaction as the application code. When used in conjunction with an ORM tool, be sure to
avoid false positives. As mentioned
in JDBC Testing Support, AbstractTransactionalTestNGSpringContextTests also
provides convenience methods that delegate to methods in JdbcTestUtils by using the aforementioned jdbcTemplate.
Furthermore, AbstractTransactionalTestNGSpringContextTests provides an executeSqlScript(..) method for running SQL
scripts against the configured DataSource.
These classes are a convenience for extension. If you do not want your test classes to be tied to a Spring-specific
class hierarchy, you can configure your own custom test classes by using @ContextConfiguration,
@TestExecutionListeners, and so on and by manually instrumenting your test class with a TestContextManager. See the
source code of AbstractTestNGSpringContextTests for an example of how to instrument your test class.