1931 lines
63 KiB
Plaintext
1931 lines
63 KiB
Plaintext
[[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.
|