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