spring-framework/framework-docs/src/docs/asciidoc/testing/testing-annotations.adoc

1931 lines
63 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[[integration-testing-annotations]]
= Annotations
This section covers annotations that you can use when you test Spring applications.
It includes the following topics:
* <<integration-testing-annotations-standard>>
* <<integration-testing-annotations-spring>>
* <<integration-testing-annotations-junit4>>
* <<integration-testing-annotations-junit-jupiter>>
* <<integration-testing-annotations-meta>>
[[integration-testing-annotations-standard]]
== Standard Annotation Support
The following annotations are supported with standard semantics for all configurations of
the Spring TestContext Framework. Note that these annotations are not specific to tests
and can be used anywhere in the Spring Framework.
* `@Autowired`
* `@Qualifier`
* `@Value`
* `@Resource` (jakarta.annotation) if JSR-250 is present
* `@ManagedBean` (jakarta.annotation) if JSR-250 is present
* `@Inject` (jakarta.inject) if JSR-330 is present
* `@Named` (jakarta.inject) if JSR-330 is present
* `@PersistenceContext` (jakarta.persistence) if JPA is present
* `@PersistenceUnit` (jakarta.persistence) if JPA is present
* `@Transactional` (org.springframework.transaction.annotation)
_with <<testcontext-tx-attribute-support, limited attribute support>>_
.JSR-250 Lifecycle Annotations
[NOTE]
====
In the Spring TestContext Framework, you can use `@PostConstruct` and `@PreDestroy` with
standard semantics on any application components configured in the `ApplicationContext`.
However, these lifecycle annotations have limited usage within an actual test class.
If a method within a test class is annotated with `@PostConstruct`, that method runs
before any before methods of the underlying test framework (for example, methods
annotated with JUnit Jupiter's `@BeforeEach`), and that applies for every test method in
the test class. On the other hand, if a method within a test class is annotated with
`@PreDestroy`, that method never runs. Therefore, within a test class, we recommend that
you use test lifecycle callbacks from the underlying test framework instead of
`@PostConstruct` and `@PreDestroy`.
====
[[integration-testing-annotations-spring]]
== Spring Testing Annotations
The Spring Framework provides the following set of Spring-specific annotations that you
can use in your unit and integration tests in conjunction with the TestContext framework.
See the corresponding javadoc for further information, including default attribute
values, attribute aliases, and other details.
Spring's testing annotations include the following:
* <<spring-testing-annotation-bootstrapwith>>
* <<spring-testing-annotation-contextconfiguration>>
* <<spring-testing-annotation-webappconfiguration>>
* <<spring-testing-annotation-contexthierarchy>>
* <<spring-testing-annotation-activeprofiles>>
* <<spring-testing-annotation-testpropertysource>>
* <<spring-testing-annotation-dynamicpropertysource>>
* <<spring-testing-annotation-dirtiescontext>>
* <<spring-testing-annotation-testexecutionlisteners>>
* <<spring-testing-annotation-recordapplicationevents>>
* <<spring-testing-annotation-commit>>
* <<spring-testing-annotation-rollback>>
* <<spring-testing-annotation-beforetransaction>>
* <<spring-testing-annotation-aftertransaction>>
* <<spring-testing-annotation-sql>>
* <<spring-testing-annotation-sqlconfig>>
* <<spring-testing-annotation-sqlmergemode>>
* <<spring-testing-annotation-sqlgroup>>
[[spring-testing-annotation-bootstrapwith]]
=== `@BootstrapWith`
`@BootstrapWith` is a class-level annotation that you can use to configure how the Spring
TestContext Framework is bootstrapped. Specifically, you can use `@BootstrapWith` to
specify a custom `TestContextBootstrapper`. See the section on
<<testcontext-bootstrapping, bootstrapping the TestContext framework>> for further details.
[[spring-testing-annotation-contextconfiguration]]
=== `@ContextConfiguration`
`@ContextConfiguration` defines class-level metadata that is used to determine how to
load and configure an `ApplicationContext` for integration tests. Specifically,
`@ContextConfiguration` declares the application context resource `locations` or the
component `classes` used to load the context.
Resource locations are typically XML configuration files or Groovy scripts located in the
classpath, while component classes are typically `@Configuration` classes. However,
resource locations can also refer to files and scripts in the file system, and component
classes can be `@Component` classes, `@Service` classes, and so on. See
<<testcontext-ctx-management-javaconfig-component-classes>> for further details.
The following example shows a `@ContextConfiguration` annotation that refers to an XML
file:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration("/test-config.xml") // <1>
class XmlApplicationContextTests {
// class body...
}
----
<1> Referring to an XML file.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration("/test-config.xml") // <1>
class XmlApplicationContextTests {
// class body...
}
----
<1> Referring to an XML file.
The following example shows a `@ContextConfiguration` annotation that refers to a class:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration(classes = TestConfig.class) // <1>
class ConfigClassApplicationContextTests {
// class body...
}
----
<1> Referring to a class.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration(classes = [TestConfig::class]) // <1>
class ConfigClassApplicationContextTests {
// class body...
}
----
<1> Referring to a class.
As an alternative or in addition to declaring resource locations or component classes,
you can use `@ContextConfiguration` to declare `ApplicationContextInitializer` classes.
The following example shows such a case:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration(initializers = CustomContextInitializer.class) // <1>
class ContextInitializerTests {
// class body...
}
----
<1> Declaring an initializer class.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration(initializers = [CustomContextInitializer::class]) // <1>
class ContextInitializerTests {
// class body...
}
----
<1> Declaring an initializer class.
You can optionally use `@ContextConfiguration` to declare the `ContextLoader` strategy as
well. Note, however, that you typically do not need to explicitly configure the loader,
since the default loader supports `initializers` and either resource `locations` or
component `classes`.
The following example uses both a location and a loader:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration(locations = "/test-context.xml", loader = CustomContextLoader.class) // <1>
class CustomLoaderXmlApplicationContextTests {
// class body...
}
----
<1> Configuring both a location and a custom loader.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration("/test-context.xml", loader = CustomContextLoader::class) // <1>
class CustomLoaderXmlApplicationContextTests {
// class body...
}
----
<1> Configuring both a location and a custom loader.
NOTE: `@ContextConfiguration` provides support for inheriting resource locations or
configuration classes as well as context initializers that are declared by superclasses
or enclosing classes.
See <<testcontext-ctx-management>>,
<<testcontext-junit-jupiter-nested-test-configuration>>, and the `@ContextConfiguration`
javadocs for further details.
[[spring-testing-annotation-webappconfiguration]]
=== `@WebAppConfiguration`
`@WebAppConfiguration` is a class-level annotation that you can use to declare that the
`ApplicationContext` loaded for an integration test should be a `WebApplicationContext`.
The mere presence of `@WebAppConfiguration` on a test class ensures that a
`WebApplicationContext` is loaded for the test, using the default value of
`"file:src/main/webapp"` for the path to the root of the web application (that is, the
resource base path). The resource base path is used behind the scenes to create a
`MockServletContext`, which serves as the `ServletContext` for the test's
`WebApplicationContext`.
The following example shows how to use the `@WebAppConfiguration` annotation:
--
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@WebAppConfiguration // <1>
class WebAppTests {
// class body...
}
----
<1> The `@WebAppConfiguration` annotation.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@WebAppConfiguration // <1>
class WebAppTests {
// class body...
}
----
<1> The `@WebAppConfiguration` annotation.
--
To override the default, you can specify a different base resource path by using the
implicit `value` attribute. Both `classpath:` and `file:` resource prefixes are
supported. If no resource prefix is supplied, the path is assumed to be a file system
resource. The following example shows how to specify a classpath resource:
--
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@WebAppConfiguration("classpath:test-web-resources") // <1>
class WebAppTests {
// class body...
}
----
<1> Specifying a classpath resource.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@WebAppConfiguration("classpath:test-web-resources") // <1>
class WebAppTests {
// class body...
}
----
<1> Specifying a classpath resource.
--
Note that `@WebAppConfiguration` must be used in conjunction with
`@ContextConfiguration`, either within a single test class or within a test class
hierarchy. See the
{api-spring-framework}/test/context/web/WebAppConfiguration.html[`@WebAppConfiguration`]
javadoc for further details.
[[spring-testing-annotation-contexthierarchy]]
=== `@ContextHierarchy`
`@ContextHierarchy` is a class-level annotation that is used to define a hierarchy of
`ApplicationContext` instances for integration tests. `@ContextHierarchy` should be
declared with a list of one or more `@ContextConfiguration` instances, each of which
defines a level in the context hierarchy. The following examples demonstrate the use of
`@ContextHierarchy` within a single test class (`@ContextHierarchy` can also be used
within a test class hierarchy):
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@ContextConfiguration("/child-config.xml")
})
class ContextHierarchyTests {
// class body...
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextHierarchy(
ContextConfiguration("/parent-config.xml"),
ContextConfiguration("/child-config.xml"))
class ContextHierarchyTests {
// class body...
}
----
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = AppConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class WebIntegrationTests {
// class body...
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@WebAppConfiguration
@ContextHierarchy(
ContextConfiguration(classes = [AppConfig::class]),
ContextConfiguration(classes = [WebConfig::class]))
class WebIntegrationTests {
// class body...
}
----
If you need to merge or override the configuration for a given level of the context
hierarchy within a test class hierarchy, you must explicitly name that level by supplying
the same value to the `name` attribute in `@ContextConfiguration` at each corresponding
level in the class hierarchy. See <<testcontext-ctx-management-ctx-hierarchies>> and the
{api-spring-framework}/test/context/ContextHierarchy.html[`@ContextHierarchy`] javadoc
for further examples.
[[spring-testing-annotation-activeprofiles]]
=== `@ActiveProfiles`
`@ActiveProfiles` is a class-level annotation that is used to declare which bean
definition profiles should be active when loading an `ApplicationContext` for an
integration test.
The following example indicates that the `dev` profile should be active:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@ActiveProfiles("dev") // <1>
class DeveloperTests {
// class body...
}
----
<1> Indicate that the `dev` profile should be active.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@ActiveProfiles("dev") // <1>
class DeveloperTests {
// class body...
}
----
<1> Indicate that the `dev` profile should be active.
The following example indicates that both the `dev` and the `integration` profiles should
be active:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@ActiveProfiles({"dev", "integration"}) // <1>
class DeveloperIntegrationTests {
// class body...
}
----
<1> Indicate that the `dev` and `integration` profiles should be active.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@ActiveProfiles(["dev", "integration"]) // <1>
class DeveloperIntegrationTests {
// class body...
}
----
<1> Indicate that the `dev` and `integration` profiles should be active.
NOTE: `@ActiveProfiles` provides support for inheriting active bean definition profiles
declared by superclasses and enclosing classes by default. You can also resolve active
bean definition profiles programmatically by implementing a custom
<<testcontext-ctx-management-env-profiles-ActiveProfilesResolver, `ActiveProfilesResolver`>>
and registering it by using the `resolver` attribute of `@ActiveProfiles`.
See <<testcontext-ctx-management-env-profiles>>,
<<testcontext-junit-jupiter-nested-test-configuration>>, and the
{api-spring-framework}/test/context/ActiveProfiles.html[`@ActiveProfiles`] javadoc for
examples and further details.
[[spring-testing-annotation-testpropertysource]]
=== `@TestPropertySource`
`@TestPropertySource` is a class-level annotation that you can use to configure the
locations of properties files and inlined properties to be added to the set of
`PropertySources` in the `Environment` for an `ApplicationContext` loaded for an
integration test.
The following example demonstrates how to declare a properties file from the classpath:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestPropertySource("/test.properties") // <1>
class MyIntegrationTests {
// class body...
}
----
<1> Get properties from `test.properties` in the root of the classpath.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestPropertySource("/test.properties") // <1>
class MyIntegrationTests {
// class body...
}
----
<1> Get properties from `test.properties` in the root of the classpath.
The following example demonstrates how to declare inlined properties:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestPropertySource(properties = { "timezone = GMT", "port: 4242" }) // <1>
class MyIntegrationTests {
// class body...
}
----
<1> Declare `timezone` and `port` properties.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestPropertySource(properties = ["timezone = GMT", "port: 4242"]) // <1>
class MyIntegrationTests {
// class body...
}
----
<1> Declare `timezone` and `port` properties.
See <<testcontext-ctx-management-property-sources>> for examples and further details.
[[spring-testing-annotation-dynamicpropertysource]]
=== `@DynamicPropertySource`
`@DynamicPropertySource` is a method-level annotation that you can use to register
_dynamic_ properties to be added to the set of `PropertySources` in the `Environment` for
an `ApplicationContext` loaded for an integration test. Dynamic properties are useful
when you do not know the value of the properties upfront for example, if the properties
are managed by an external resource such as for a container managed by the
https://www.testcontainers.org/[Testcontainers] project.
The following example demonstrates how to register a dynamic property:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
class MyIntegrationTests {
static MyExternalServer server = // ...
@DynamicPropertySource // <1>
static void dynamicProperties(DynamicPropertyRegistry registry) { // <2>
registry.add("server.port", server::getPort); // <3>
}
// tests ...
}
----
<1> Annotate a `static` method with `@DynamicPropertySource`.
<2> Accept a `DynamicPropertyRegistry` as an argument.
<3> Register a dynamic `server.port` property to be retrieved lazily from the server.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
class MyIntegrationTests {
companion object {
@JvmStatic
val server: MyExternalServer = // ...
@DynamicPropertySource // <1>
@JvmStatic
fun dynamicProperties(registry: DynamicPropertyRegistry) { // <2>
registry.add("server.port", server::getPort) // <3>
}
}
// tests ...
}
----
<1> Annotate a `static` method with `@DynamicPropertySource`.
<2> Accept a `DynamicPropertyRegistry` as an argument.
<3> Register a dynamic `server.port` property to be retrieved lazily from the server.
See <<testcontext-ctx-management-dynamic-property-sources>> for further details.
[[spring-testing-annotation-dirtiescontext]]
=== `@DirtiesContext`
`@DirtiesContext` indicates that the underlying Spring `ApplicationContext` has been
dirtied during the execution of a test (that is, the test modified or corrupted it in
some manner -- for example, by changing the state of a singleton bean) and should be
closed. When an application context is marked as dirty, it is removed from the testing
framework's cache and closed. As a consequence, the underlying Spring container is
rebuilt for any subsequent test that requires a context with the same configuration
metadata.
You can use `@DirtiesContext` as both a class-level and a method-level annotation within
the same class or class hierarchy. In such scenarios, the `ApplicationContext` is marked
as dirty before or after any such annotated method as well as before or after the current
test class, depending on the configured `methodMode` and `classMode`.
The following examples explain when the context would be dirtied for various
configuration scenarios:
* Before the current test class, when declared on a class with class mode set to
`BEFORE_CLASS`.
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext(classMode = BEFORE_CLASS) // <1>
class FreshContextTests {
// some tests that require a new Spring container
}
----
<1> Dirty the context before the current test class.
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@DirtiesContext(classMode = BEFORE_CLASS) // <1>
class FreshContextTests {
// some tests that require a new Spring container
}
----
<1> Dirty the context before the current test class.
* After the current test class, when declared on a class with class mode set to
`AFTER_CLASS` (i.e., the default class mode).
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext // <1>
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
----
<1> Dirty the context after the current test class.
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@DirtiesContext // <1>
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
----
<1> Dirty the context after the current test class.
* Before each test method in the current test class, when declared on a class with class
mode set to `BEFORE_EACH_TEST_METHOD.`
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD) // <1>
class FreshContextTests {
// some tests that require a new Spring container
}
----
<1> Dirty the context before each test method.
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD) // <1>
class FreshContextTests {
// some tests that require a new Spring container
}
----
<1> Dirty the context before each test method.
* After each test method in the current test class, when declared on a class with class
mode set to `AFTER_EACH_TEST_METHOD.`
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) // <1>
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
----
<1> Dirty the context after each test method.
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) // <1>
class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
----
<1> Dirty the context after each test method.
* Before the current test, when declared on a method with the method mode set to
`BEFORE_METHOD`.
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext(methodMode = BEFORE_METHOD) // <1>
@Test
void testProcessWhichRequiresFreshAppCtx() {
// some logic that requires a new Spring container
}
----
<1> Dirty the context before the current test method.
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@DirtiesContext(methodMode = BEFORE_METHOD) // <1>
@Test
fun testProcessWhichRequiresFreshAppCtx() {
// some logic that requires a new Spring container
}
----
<1> Dirty the context before the current test method.
* After the current test, when declared on a method with the method mode set to
`AFTER_METHOD` (i.e., the default method mode).
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext // <1>
@Test
void testProcessWhichDirtiesAppCtx() {
// some logic that results in the Spring container being dirtied
}
----
<1> Dirty the context after the current test method.
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@DirtiesContext // <1>
@Test
fun testProcessWhichDirtiesAppCtx() {
// some logic that results in the Spring container being dirtied
}
----
<1> Dirty the context after the current test method.
If you use `@DirtiesContext` in a test whose context is configured as part of a context
hierarchy with `@ContextHierarchy`, you can use the `hierarchyMode` flag to control how
the context cache is cleared. By default, an exhaustive algorithm is used to clear the
context cache, including not only the current level but also all other context
hierarchies that share an ancestor context common to the current test. All
`ApplicationContext` instances that reside in a sub-hierarchy of the common ancestor
context are removed from the context cache and closed. If the exhaustive algorithm is
overkill for a particular use case, you can specify the simpler current level algorithm,
as the following example shows.
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@ContextConfiguration("/child-config.xml")
})
class BaseTests {
// class body...
}
class ExtendedTests extends BaseTests {
@Test
@DirtiesContext(hierarchyMode = CURRENT_LEVEL) // <1>
void test() {
// some logic that results in the child context being dirtied
}
}
----
<1> Use the current-level algorithm.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextHierarchy(
ContextConfiguration("/parent-config.xml"),
ContextConfiguration("/child-config.xml"))
open class BaseTests {
// class body...
}
class ExtendedTests : BaseTests() {
@Test
@DirtiesContext(hierarchyMode = CURRENT_LEVEL) // <1>
fun test() {
// some logic that results in the child context being dirtied
}
}
----
<1> Use the current-level algorithm.
For further details regarding the `EXHAUSTIVE` and `CURRENT_LEVEL` algorithms, see the
{api-spring-framework}/test/annotation/DirtiesContext.HierarchyMode.html[`DirtiesContext.HierarchyMode`]
javadoc.
[[spring-testing-annotation-testexecutionlisteners]]
=== `@TestExecutionListeners`
`@TestExecutionListeners` is used to register listeners for a particular test class, its
subclasses, and its nested classes. If you wish to register a listener globally, you
should register it via the automatic discovery mechanism described in
<<testcontext-tel-config>>.
The following example shows how to register two `TestExecutionListener` implementations:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class}) // <1>
class CustomTestExecutionListenerTests {
// class body...
}
----
<1> Register two `TestExecutionListener` implementations.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestExecutionListeners(CustomTestExecutionListener::class, AnotherTestExecutionListener::class) // <1>
class CustomTestExecutionListenerTests {
// class body...
}
----
<1> Register two `TestExecutionListener` implementations.
By default, `@TestExecutionListeners` provides support for inheriting listeners from
superclasses or enclosing classes. See
<<testcontext-junit-jupiter-nested-test-configuration>> and the
{api-spring-framework}/test/context/TestExecutionListeners.html[`@TestExecutionListeners`
javadoc] for an example and further details. If you discover that you need to switch
back to using the default `TestExecutionListener` implementations, see the note
in <<testcontext-tel-config-registering-tels>>.
[[spring-testing-annotation-recordapplicationevents]]
=== `@RecordApplicationEvents`
`@RecordApplicationEvents` is a class-level annotation that is used to instruct the
_Spring TestContext Framework_ to record all application events that are published in the
`ApplicationContext` during the execution of a single test.
The recorded events can be accessed via the `ApplicationEvents` API within tests.
See <<testcontext-application-events>> and the
{api-spring-framework}/test/context/event/RecordApplicationEvents.html[`@RecordApplicationEvents`
javadoc] for an example and further details.
[[spring-testing-annotation-commit]]
=== `@Commit`
`@Commit` indicates that the transaction for a transactional test method should be
committed after the test method has completed. You can use `@Commit` as a direct
replacement for `@Rollback(false)` to more explicitly convey the intent of the code.
Analogous to `@Rollback`, `@Commit` can also be declared as a class-level or method-level
annotation.
The following example shows how to use the `@Commit` annotation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Commit // <1>
@Test
void testProcessWithoutRollback() {
// ...
}
----
<1> Commit the result of the test to the database.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Commit // <1>
@Test
fun testProcessWithoutRollback() {
// ...
}
----
<1> Commit the result of the test to the database.
[[spring-testing-annotation-rollback]]
=== `@Rollback`
`@Rollback` indicates whether the transaction for a transactional test method should be
rolled back after the test method has completed. If `true`, the transaction is rolled
back. Otherwise, the transaction is committed (see also
<<spring-testing-annotation-commit>>). Rollback for integration tests in the Spring
TestContext Framework defaults to `true` even if `@Rollback` is not explicitly declared.
When declared as a class-level annotation, `@Rollback` defines the default rollback
semantics for all test methods within the test class hierarchy. When declared as a
method-level annotation, `@Rollback` defines rollback semantics for the specific test
method, potentially overriding class-level `@Rollback` or `@Commit` semantics.
The following example causes a test method's result to not be rolled back (that is, the
result is committed to the database):
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Rollback(false) // <1>
@Test
void testProcessWithoutRollback() {
// ...
}
----
<1> Do not roll back the result.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Rollback(false) // <1>
@Test
fun testProcessWithoutRollback() {
// ...
}
----
<1> Do not roll back the result.
[[spring-testing-annotation-beforetransaction]]
=== `@BeforeTransaction`
`@BeforeTransaction` indicates that the annotated `void` method should be run before a
transaction is started, for test methods that have been configured to run within a
transaction by using Spring's `@Transactional` annotation. `@BeforeTransaction` methods
are not required to be `public` and may be declared on Java 8-based interface default
methods.
The following example shows how to use the `@BeforeTransaction` annotation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@BeforeTransaction // <1>
void beforeTransaction() {
// logic to be run before a transaction is started
}
----
<1> Run this method before a transaction.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@BeforeTransaction // <1>
fun beforeTransaction() {
// logic to be run before a transaction is started
}
----
<1> Run this method before a transaction.
[[spring-testing-annotation-aftertransaction]]
=== `@AfterTransaction`
`@AfterTransaction` indicates that the annotated `void` method should be run after a
transaction is ended, for test methods that have been configured to run within a
transaction by using Spring's `@Transactional` annotation. `@AfterTransaction` methods
are not required to be `public` and may be declared on Java 8-based interface default
methods.
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@AfterTransaction // <1>
void afterTransaction() {
// logic to be run after a transaction has ended
}
----
<1> Run this method after a transaction.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@AfterTransaction // <1>
fun afterTransaction() {
// logic to be run after a transaction has ended
}
----
<1> Run this method after a transaction.
[[spring-testing-annotation-sql]]
=== `@Sql`
`@Sql` is used to annotate a test class or test method to configure SQL scripts to be run
against a given database during integration tests. The following example shows how to use
it:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"}) // <1>
void userTest() {
// run code that relies on the test schema and test data
}
----
<1> Run two scripts for this test.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
@Sql("/test-schema.sql", "/test-user-data.sql") // <1>
fun userTest() {
// run code that relies on the test schema and test data
}
----
<1> Run two scripts for this test.
See <<testcontext-executing-sql-declaratively>> for further details.
[[spring-testing-annotation-sqlconfig]]
=== `@SqlConfig`
`@SqlConfig` defines metadata that is used to determine how to parse and run SQL scripts
configured with the `@Sql` annotation. The following example shows how to use it:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@Sql(
scripts = "/test-user-data.sql",
config = @SqlConfig(commentPrefix = "`", separator = "@@") // <1>
)
void userTest() {
// run code that relies on the test data
}
----
<1> Set the comment prefix and the separator in SQL scripts.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
@Sql("/test-user-data.sql", config = SqlConfig(commentPrefix = "`", separator = "@@")) // <1>
fun userTest() {
// run code that relies on the test data
}
----
<1> Set the comment prefix and the separator in SQL scripts.
[[spring-testing-annotation-sqlmergemode]]
=== `@SqlMergeMode`
`@SqlMergeMode` is used to annotate a test class or test method to configure whether
method-level `@Sql` declarations are merged with class-level `@Sql` declarations. If
`@SqlMergeMode` is not declared on a test class or test method, the `OVERRIDE` merge mode
will be used by default. With the `OVERRIDE` mode, method-level `@Sql` declarations will
effectively override class-level `@Sql` declarations.
Note that a method-level `@SqlMergeMode` declaration overrides a class-level declaration.
The following example shows how to use `@SqlMergeMode` at the class level.
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
@SqlMergeMode(MERGE) // <1>
class UserTests {
@Test
@Sql("/user-test-data-001.sql")
void standardUserProfile() {
// run code that relies on test data set 001
}
}
----
<1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
@Sql("/test-schema.sql")
@SqlMergeMode(MERGE) // <1>
class UserTests {
@Test
@Sql("/user-test-data-001.sql")
fun standardUserProfile() {
// run code that relies on test data set 001
}
}
----
<1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class.
The following example shows how to use `@SqlMergeMode` at the method level.
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
class UserTests {
@Test
@Sql("/user-test-data-001.sql")
@SqlMergeMode(MERGE) // <1>
void standardUserProfile() {
// run code that relies on test data set 001
}
}
----
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
@Sql("/test-schema.sql")
class UserTests {
@Test
@Sql("/user-test-data-001.sql")
@SqlMergeMode(MERGE) // <1>
fun standardUserProfile() {
// run code that relies on test data set 001
}
}
----
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
[[spring-testing-annotation-sqlgroup]]
=== `@SqlGroup`
`@SqlGroup` is a container annotation that aggregates several `@Sql` annotations. You can
use `@SqlGroup` natively to declare several nested `@Sql` annotations, or you can use it
in conjunction with Java 8's support for repeatable annotations, where `@Sql` can be
declared several times on the same class or method, implicitly generating this container
annotation. The following example shows how to declare an SQL group:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@SqlGroup({ // <1>
@Sql(scripts = "/test-schema.sql", config = @SqlConfig(commentPrefix = "`")),
@Sql("/test-user-data.sql")
})
void userTest() {
// run code that uses the test schema and test data
}
----
<1> Declare a group of SQL scripts.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
@SqlGroup( // <1>
Sql("/test-schema.sql", config = SqlConfig(commentPrefix = "`")),
Sql("/test-user-data.sql"))
fun userTest() {
// run code that uses the test schema and test data
}
----
<1> Declare a group of SQL scripts.
[[integration-testing-annotations-junit4]]
== Spring JUnit 4 Testing Annotations
The following annotations are supported only when used in conjunction with the
<<testcontext-junit4-runner, SpringRunner>>, <<testcontext-junit4-rules, Spring's JUnit 4
rules>>, or <<testcontext-support-classes-junit4, Spring's JUnit 4 support classes>>:
* <<integration-testing-annotations-junit4-ifprofilevalue>>
* <<integration-testing-annotations-junit4-profilevaluesourceconfiguration>>
* <<integration-testing-annotations-junit4-timed>>
* <<integration-testing-annotations-junit4-repeat>>
[[integration-testing-annotations-junit4-ifprofilevalue]]
=== `@IfProfileValue`
`@IfProfileValue` indicates that the annotated test is enabled for a specific testing
environment. If the configured `ProfileValueSource` returns a matching `value` for the
provided `name`, the test is enabled. Otherwise, the test is disabled and, effectively,
ignored.
You can apply `@IfProfileValue` at the class level, the method level, or both.
Class-level usage of `@IfProfileValue` takes precedence over method-level usage for any
methods within that class or its subclasses. Specifically, a test is enabled if it is
enabled both at the class level and at the method level. The absence of `@IfProfileValue`
means the test is implicitly enabled. This is analogous to the semantics of JUnit 4's
`@Ignore` annotation, except that the presence of `@Ignore` always disables a test.
The following example shows a test that has an `@IfProfileValue` annotation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@IfProfileValue(name="java.vendor", value="Oracle Corporation") // <1>
@Test
public void testProcessWhichRunsOnlyOnOracleJvm() {
// some logic that should run only on Java VMs from Oracle Corporation
}
----
<1> Run this test only when the Java vendor is "Oracle Corporation".
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@IfProfileValue(name="java.vendor", value="Oracle Corporation") // <1>
@Test
fun testProcessWhichRunsOnlyOnOracleJvm() {
// some logic that should run only on Java VMs from Oracle Corporation
}
----
<1> Run this test only when the Java vendor is "Oracle Corporation".
Alternatively, you can configure `@IfProfileValue` with a list of `values` (with `OR`
semantics) to achieve TestNG-like support for test groups in a JUnit 4 environment.
Consider the following example:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"}) // <1>
@Test
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
// some logic that should run only for unit and integration test groups
}
----
<1> Run this test for unit tests and integration tests.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@IfProfileValue(name="test-groups", values=["unit-tests", "integration-tests"]) // <1>
@Test
fun testProcessWhichRunsForUnitOrIntegrationTestGroups() {
// some logic that should run only for unit and integration test groups
}
----
<1> Run this test for unit tests and integration tests.
[[integration-testing-annotations-junit4-profilevaluesourceconfiguration]]
=== `@ProfileValueSourceConfiguration`
`@ProfileValueSourceConfiguration` is a class-level annotation that specifies what type
of `ProfileValueSource` to use when retrieving profile values configured through the
`@IfProfileValue` annotation. If `@ProfileValueSourceConfiguration` is not declared for a
test, `SystemProfileValueSource` is used by default. The following example shows how to
use `@ProfileValueSourceConfiguration`:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ProfileValueSourceConfiguration(CustomProfileValueSource.class) // <1>
public class CustomProfileValueSourceTests {
// class body...
}
----
<1> Use a custom profile value source.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ProfileValueSourceConfiguration(CustomProfileValueSource::class) // <1>
class CustomProfileValueSourceTests {
// class body...
}
----
<1> Use a custom profile value source.
[[integration-testing-annotations-junit4-timed]]
=== `@Timed`
`@Timed` indicates that the annotated test method must finish execution in a specified
time period (in milliseconds). If the text execution time exceeds the specified time
period, the test fails.
The time period includes running the test method itself, any repetitions of the test (see
`@Repeat`), as well as any setting up or tearing down of the test fixture. The following
example shows how to use it:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Timed(millis = 1000) // <1>
public void testProcessWithOneSecondTimeout() {
// some logic that should not take longer than 1 second to run
}
----
<1> Set the time period for the test to one second.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Timed(millis = 1000) // <1>
fun testProcessWithOneSecondTimeout() {
// some logic that should not take longer than 1 second to run
}
----
<1> Set the time period for the test to one second.
Spring's `@Timed` annotation has different semantics than JUnit 4's `@Test(timeout=...)`
support. Specifically, due to the manner in which JUnit 4 handles test execution timeouts
(that is, by executing the test method in a separate `Thread`), `@Test(timeout=...)`
preemptively fails the test if the test takes too long. Spring's `@Timed`, on the other
hand, does not preemptively fail the test but rather waits for the test to complete
before failing.
[[integration-testing-annotations-junit4-repeat]]
=== `@Repeat`
`@Repeat` indicates that the annotated test method must be run repeatedly. The number of
times that the test method is to be run is specified in the annotation.
The scope of execution to be repeated includes execution of the test method itself as
well as any setting up or tearing down of the test fixture. When used with the
<<testcontext-junit4-rules, `SpringMethodRule`>>, the scope additionally includes
preparation of the test instance by `TestExecutionListener` implementations. The
following example shows how to use the `@Repeat` annotation:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Repeat(10) // <1>
@Test
public void testProcessRepeatedly() {
// ...
}
----
<1> Repeat this test ten times.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Repeat(10) // <1>
@Test
fun testProcessRepeatedly() {
// ...
}
----
<1> Repeat this test ten times.
[[integration-testing-annotations-junit-jupiter]]
== Spring JUnit Jupiter Testing Annotations
The following annotations are supported when used in conjunction with the
<<testcontext-junit-jupiter-extension, `SpringExtension`>> and JUnit Jupiter
(that is, the programming model in JUnit 5):
* <<integration-testing-annotations-junit-jupiter-springjunitconfig>>
* <<integration-testing-annotations-junit-jupiter-springjunitwebconfig>>
* <<integration-testing-annotations-testconstructor>>
* <<integration-testing-annotations-nestedtestconfiguration>>
* <<integration-testing-annotations-junit-jupiter-enabledif>>
* <<integration-testing-annotations-junit-jupiter-disabledif>>
[[integration-testing-annotations-junit-jupiter-springjunitconfig]]
=== `@SpringJUnitConfig`
`@SpringJUnitConfig` is a composed annotation that combines
`@ExtendWith(SpringExtension.class)` from JUnit Jupiter with `@ContextConfiguration` from
the Spring TestContext Framework. It can be used at the class level as a drop-in
replacement for `@ContextConfiguration`. With regard to configuration options, the only
difference between `@ContextConfiguration` and `@SpringJUnitConfig` is that component
classes may be declared with the `value` attribute in `@SpringJUnitConfig`.
The following example shows how to use the `@SpringJUnitConfig` annotation to specify a
configuration class:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class) // <1>
class ConfigurationClassJUnitJupiterSpringTests {
// class body...
}
----
<1> Specify the configuration class.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class) // <1>
class ConfigurationClassJUnitJupiterSpringTests {
// class body...
}
----
<1> Specify the configuration class.
The following example shows how to use the `@SpringJUnitConfig` annotation to specify the
location of a configuration file:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(locations = "/test-config.xml") // <1>
class XmlJUnitJupiterSpringTests {
// class body...
}
----
<1> Specify the location of a configuration file.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(locations = ["/test-config.xml"]) // <1>
class XmlJUnitJupiterSpringTests {
// class body...
}
----
<1> Specify the location of a configuration file.
See <<testcontext-ctx-management>> as well as the javadoc for
{api-spring-framework}/test/context/junit/jupiter/SpringJUnitConfig.html[`@SpringJUnitConfig`]
and `@ContextConfiguration` for further details.
[[integration-testing-annotations-junit-jupiter-springjunitwebconfig]]
=== `@SpringJUnitWebConfig`
`@SpringJUnitWebConfig` is a composed annotation that combines
`@ExtendWith(SpringExtension.class)` from JUnit Jupiter with `@ContextConfiguration` and
`@WebAppConfiguration` from the Spring TestContext Framework. You can use it at the class
level as a drop-in replacement for `@ContextConfiguration` and `@WebAppConfiguration`.
With regard to configuration options, the only difference between `@ContextConfiguration`
and `@SpringJUnitWebConfig` is that you can declare component classes by using the
`value` attribute in `@SpringJUnitWebConfig`. In addition, you can override the `value`
attribute from `@WebAppConfiguration` only by using the `resourcePath` attribute in
`@SpringJUnitWebConfig`.
The following example shows how to use the `@SpringJUnitWebConfig` annotation to specify
a configuration class:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig(TestConfig.class) // <1>
class ConfigurationClassJUnitJupiterSpringWebTests {
// class body...
}
----
<1> Specify the configuration class.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig(TestConfig::class) // <1>
class ConfigurationClassJUnitJupiterSpringWebTests {
// class body...
}
----
<1> Specify the configuration class.
The following example shows how to use the `@SpringJUnitWebConfig` annotation to specify the
location of a configuration file:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig(locations = "/test-config.xml") // <1>
class XmlJUnitJupiterSpringWebTests {
// class body...
}
----
<1> Specify the location of a configuration file.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig(locations = ["/test-config.xml"]) // <1>
class XmlJUnitJupiterSpringWebTests {
// class body...
}
----
<1> Specify the location of a configuration file.
See <<testcontext-ctx-management>> as well as the javadoc for
{api-spring-framework}/test/context/junit/jupiter/web/SpringJUnitWebConfig.html[`@SpringJUnitWebConfig`],
{api-spring-framework}/test/context/ContextConfiguration.html[`@ContextConfiguration`], and
{api-spring-framework}/test/context/web/WebAppConfiguration.html[`@WebAppConfiguration`]
for further details.
[[integration-testing-annotations-testconstructor]]
=== `@TestConstructor`
`@TestConstructor` is a type-level annotation that is used to configure how the parameters
of a test class constructor are autowired from components in the test's
`ApplicationContext`.
If `@TestConstructor` is not present or meta-present on a test class, the default _test
constructor autowire mode_ will be used. See the tip below for details on how to change
the default mode. Note, however, that a local declaration of `@Autowired` on a
constructor takes precedence over both `@TestConstructor` and the default mode.
.Changing the default test constructor autowire mode
[TIP]
=====
The default _test constructor autowire mode_ can be changed by setting the
`spring.test.constructor.autowire.mode` JVM system property to `all`. Alternatively, the
default mode may be set via the
<<appendix.adoc#appendix-spring-properties,`SpringProperties`>> mechanism.
As of Spring Framework 5.3, the default mode may also be configured as a
https://junit.org/junit5/docs/current/user-guide/#running-tests-config-params[JUnit Platform configuration parameter].
If the `spring.test.constructor.autowire.mode` property is not set, test class
constructors will not be automatically autowired.
=====
NOTE: As of Spring Framework 5.2, `@TestConstructor` is only supported in conjunction
with the `SpringExtension` for use with JUnit Jupiter. Note that the `SpringExtension` is
often automatically registered for you for example, when using annotations such as
`@SpringJUnitConfig` and `@SpringJUnitWebConfig` or various test-related annotations from
Spring Boot Test.
[[integration-testing-annotations-nestedtestconfiguration]]
=== `@NestedTestConfiguration`
`@NestedTestConfiguration` is a type-level annotation that is used to configure how
Spring test configuration annotations are processed within enclosing class hierarchies
for inner test classes.
If `@NestedTestConfiguration` is not present or meta-present on a test class, in its
supertype hierarchy, or in its enclosing class hierarchy, the default _enclosing
configuration inheritance mode_ will be used. See the tip below for details on how to
change the default mode.
.Changing the default enclosing configuration inheritance mode
[TIP]
=====
The default _enclosing configuration inheritance mode_ is `INHERIT`, but it can be
changed by setting the `spring.test.enclosing.configuration` JVM system property to
`OVERRIDE`. Alternatively, the default mode may be set via the
<<appendix.adoc#appendix-spring-properties,`SpringProperties`>> mechanism.
=====
The <<testcontext-framework>> honors `@NestedTestConfiguration` semantics for the
following annotations.
* <<spring-testing-annotation-bootstrapwith>>
* <<spring-testing-annotation-contextconfiguration>>
* <<spring-testing-annotation-webappconfiguration>>
* <<spring-testing-annotation-contexthierarchy>>
* <<spring-testing-annotation-activeprofiles>>
* <<spring-testing-annotation-testpropertysource>>
* <<spring-testing-annotation-dynamicpropertysource>>
* <<spring-testing-annotation-dirtiescontext>>
* <<spring-testing-annotation-testexecutionlisteners>>
* <<spring-testing-annotation-recordapplicationevents>>
* <<testcontext-tx,`@Transactional`>>
* <<spring-testing-annotation-commit>>
* <<spring-testing-annotation-rollback>>
* <<spring-testing-annotation-sql>>
* <<spring-testing-annotation-sqlconfig>>
* <<spring-testing-annotation-sqlmergemode>>
* <<integration-testing-annotations-testconstructor>>
NOTE: The use of `@NestedTestConfiguration` typically only makes sense in conjunction
with `@Nested` test classes in JUnit Jupiter; however, there may be other testing
frameworks with support for Spring and nested test classes that make use of this
annotation.
See <<testcontext-junit-jupiter-nested-test-configuration>> for an example and further
details.
[[integration-testing-annotations-junit-jupiter-enabledif]]
=== `@EnabledIf`
`@EnabledIf` is used to signal that the annotated JUnit Jupiter test class or test method
is enabled and should be run if the supplied `expression` evaluates to `true`.
Specifically, if the expression evaluates to `Boolean.TRUE` or a `String` equal to `true`
(ignoring case), the test is enabled. When applied at the class level, all test methods
within that class are automatically enabled by default as well.
Expressions can be any of the following:
* <<core.adoc#expressions, Spring Expression Language>> (SpEL) expression. For example:
`@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")`
* Placeholder for a property available in the Spring <<core.adoc#beans-environment, `Environment`>>.
For example: `@EnabledIf("${smoke.tests.enabled}")`
* Text literal. For example: `@EnabledIf("true")`
Note, however, that a text literal that is not the result of dynamic resolution of a
property placeholder is of zero practical value, since `@EnabledIf("false")` is
equivalent to `@Disabled` and `@EnabledIf("true")` is logically meaningless.
You can use `@EnabledIf` as a meta-annotation to create custom composed annotations. For
example, you can create a custom `@EnabledOnMac` annotation as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@EnabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Enabled on Mac OS"
)
public @interface EnabledOnMac {}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@EnabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Enabled on Mac OS"
)
annotation class EnabledOnMac {}
----
[NOTE]
====
`@EnabledOnMac` is meant only as an example of what is possible. If you have that exact
use case, please use the built-in `@EnabledOnOs(MAC)` support in JUnit Jupiter.
====
[WARNING]
====
Since JUnit 5.7, JUnit Jupiter also has a condition annotation named `@EnabledIf`. Thus,
if you wish to use Spring's `@EnabledIf` support make sure you import the annotation type
from the correct package.
====
[[integration-testing-annotations-junit-jupiter-disabledif]]
=== `@DisabledIf`
`@DisabledIf` is used to signal that the annotated JUnit Jupiter test class or test
method is disabled and should not be run if the supplied `expression` evaluates to
`true`. Specifically, if the expression evaluates to `Boolean.TRUE` or a `String` equal
to `true` (ignoring case), the test is disabled. When applied at the class level, all
test methods within that class are automatically disabled as well.
Expressions can be any of the following:
* <<core.adoc#expressions, Spring Expression Language>> (SpEL) expression. For example:
`@DisabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")`
* Placeholder for a property available in the Spring <<core.adoc#beans-environment, `Environment`>>.
For example: `@DisabledIf("${smoke.tests.disabled}")`
* Text literal. For example: `@DisabledIf("true")`
Note, however, that a text literal that is not the result of dynamic resolution of a
property placeholder is of zero practical value, since `@DisabledIf("true")` is
equivalent to `@Disabled` and `@DisabledIf("false")` is logically meaningless.
You can use `@DisabledIf` as a meta-annotation to create custom composed annotations. For
example, you can create a custom `@DisabledOnMac` annotation as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@DisabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Disabled on Mac OS"
)
public @interface DisabledOnMac {}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@DisabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Disabled on Mac OS"
)
annotation class DisabledOnMac {}
----
[NOTE]
====
`@DisabledOnMac` is meant only as an example of what is possible. If you have that exact
use case, please use the built-in `@DisabledOnOs(MAC)` support in JUnit Jupiter.
====
[WARNING]
====
Since JUnit 5.7, JUnit Jupiter also has a condition annotation named `@DisabledIf`. Thus,
if you wish to use Spring's `@DisabledIf` support make sure you import the annotation type
from the correct package.
====
[[integration-testing-annotations-meta]]
== Meta-Annotation Support for Testing
You can use most test-related annotations as
<<core.adoc#beans-meta-annotations, meta-annotations>> to create custom composed
annotations and reduce configuration duplication across a test suite.
You can use each of the following as a meta-annotation in conjunction with the
<<testcontext-framework, TestContext framework>>.
* `@BootstrapWith`
* `@ContextConfiguration`
* `@ContextHierarchy`
* `@ActiveProfiles`
* `@TestPropertySource`
* `@DirtiesContext`
* `@WebAppConfiguration`
* `@TestExecutionListeners`
* `@Transactional`
* `@BeforeTransaction`
* `@AfterTransaction`
* `@Commit`
* `@Rollback`
* `@Sql`
* `@SqlConfig`
* `@SqlMergeMode`
* `@SqlGroup`
* `@Repeat` _(only supported on JUnit 4)_
* `@Timed` _(only supported on JUnit 4)_
* `@IfProfileValue` _(only supported on JUnit 4)_
* `@ProfileValueSourceConfiguration` _(only supported on JUnit 4)_
* `@SpringJUnitConfig` _(only supported on JUnit Jupiter)_
* `@SpringJUnitWebConfig` _(only supported on JUnit Jupiter)_
* `@TestConstructor` _(only supported on JUnit Jupiter)_
* `@NestedTestConfiguration` _(only supported on JUnit Jupiter)_
* `@EnabledIf` _(only supported on JUnit Jupiter)_
* `@DisabledIf` _(only supported on JUnit Jupiter)_
Consider the following example:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RunWith(SpringRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class OrderRepositoryTests { }
@RunWith(SpringRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class UserRepositoryTests { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RunWith(SpringRunner::class)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@ActiveProfiles("dev")
@Transactional
class OrderRepositoryTests { }
@RunWith(SpringRunner::class)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@ActiveProfiles("dev")
@Transactional
class UserRepositoryTests { }
----
If we discover that we are repeating the preceding configuration across our JUnit 4-based
test suite, we can reduce the duplication by introducing a custom composed annotation
that centralizes the common test configuration for Spring, as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTestConfig { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@ActiveProfiles("dev")
@Transactional
annotation class TransactionalDevTestConfig { }
----
Then we can use our custom `@TransactionalDevTestConfig` annotation to simplify the
configuration of individual JUnit 4 based test classes, as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RunWith(SpringRunner.class)
@TransactionalDevTestConfig
public class OrderRepositoryTests { }
@RunWith(SpringRunner.class)
@TransactionalDevTestConfig
public class UserRepositoryTests { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RunWith(SpringRunner::class)
@TransactionalDevTestConfig
class OrderRepositoryTests
@RunWith(SpringRunner::class)
@TransactionalDevTestConfig
class UserRepositoryTests
----
If we write tests that use JUnit Jupiter, we can reduce code duplication even further,
since annotations in JUnit 5 can also be used as meta-annotations. Consider the following
example:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
class OrderRepositoryTests { }
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
class UserRepositoryTests { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@ActiveProfiles("dev")
@Transactional
class OrderRepositoryTests { }
@ExtendWith(SpringExtension::class)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@ActiveProfiles("dev")
@Transactional
class UserRepositoryTests { }
----
If we discover that we are repeating the preceding configuration across our JUnit
Jupiter-based test suite, we can reduce the duplication by introducing a custom composed
annotation that centralizes the common test configuration for Spring and JUnit Jupiter,
as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTestConfig { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@ExtendWith(SpringExtension::class)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@ActiveProfiles("dev")
@Transactional
annotation class TransactionalDevTestConfig { }
----
Then we can use our custom `@TransactionalDevTestConfig` annotation to simplify the
configuration of individual JUnit Jupiter based test classes, as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@TransactionalDevTestConfig
class OrderRepositoryTests { }
@TransactionalDevTestConfig
class UserRepositoryTests { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@TransactionalDevTestConfig
class OrderRepositoryTests { }
@TransactionalDevTestConfig
class UserRepositoryTests { }
----
Since JUnit Jupiter supports the use of `@Test`, `@RepeatedTest`, `ParameterizedTest`,
and others as meta-annotations, you can also create custom composed annotations at the
test method level. For example, if we wish to create a composed annotation that combines
the `@Test` and `@Tag` annotations from JUnit Jupiter with the `@Transactional`
annotation from Spring, we could create an `@TransactionalIntegrationTest` annotation, as
follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@Tag("integration-test") // org.junit.jupiter.api.Tag
@Test // org.junit.jupiter.api.Test
public @interface TransactionalIntegrationTest { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@Transactional
@Tag("integration-test") // org.junit.jupiter.api.Tag
@Test // org.junit.jupiter.api.Test
annotation class TransactionalIntegrationTest { }
----
Then we can use our custom `@TransactionalIntegrationTest` annotation to simplify the
configuration of individual JUnit Jupiter based test methods, as follows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@TransactionalIntegrationTest
void saveOrder() { }
@TransactionalIntegrationTest
void deleteOrder() { }
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@TransactionalIntegrationTest
fun saveOrder() { }
@TransactionalIntegrationTest
fun deleteOrder() { }
----
For further details, see the
https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model[Spring Annotation Programming Model]
wiki page.