Spring Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

205 lines
5.5 KiB

[[integration-testing-annotations-meta]]
= Meta-Annotation Support for Testing
You can use most test-related annotations as
xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[meta-annotations] to
create custom composed annotations and reduce configuration duplication across a test
suite.
For example, you can use each of the following as a meta-annotation in conjunction with
the xref:testing/testcontext-framework.adoc[TestContext framework].
* `@BootstrapWith`
* `@ContextConfiguration`
* `@ContextHierarchy`
* `@ContextCustomizerFactories`
* `@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 test classes that use the `SpringExtension` with JUnit Jupiter:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {AppConfig.class, TestDataAccessConfig.class})
@ActiveProfiles("dev")
@Transactional
class OrderRepositoryTests { }
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {AppConfig.class, TestDataAccessConfig.class})
@ActiveProfiles("dev")
@Transactional
class UserRepositoryTests { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@ExtendWith(SpringExtension::class)
@ContextConfiguration(classes = [AppConfig::class, TestDataAccessConfig::class])
@ActiveProfiles("dev")
@Transactional
class OrderRepositoryTests { }
@ExtendWith(SpringExtension::class)
@ContextConfiguration(classes = [AppConfig::class, TestDataAccessConfig::class])
@ActiveProfiles("dev")
@Transactional
class UserRepositoryTests { }
----
======
If we discover that we are repeating the preceding configuration across our 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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {AppConfig.class, TestDataAccessConfig.class})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTestConfig { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@ExtendWith(SpringExtension::class)
@ContextConfiguration(classes = [AppConfig::class, TestDataAccessConfig::class])
@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@TransactionalDevTestConfig
class OrderRepositoryTests { }
@TransactionalDevTestConfig
class UserRepositoryTests { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@Tag("integration-test") // org.junit.jupiter.api.Tag
@Test // org.junit.jupiter.api.Test
public @interface TransactionalIntegrationTest { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@TransactionalIntegrationTest
void saveOrder() { }
@TransactionalIntegrationTest
void deleteOrder() { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@TransactionalIntegrationTest
fun saveOrder() { }
@TransactionalIntegrationTest
fun deleteOrder() { }
----
======
For further details, see the
{spring-framework-wiki}/Spring-Annotation-Programming-Model[Spring Annotation Programming Model]
wiki page.