Document JUnit Jupiter annotation support in the reference manual

Issue: SPR-14524
This commit is contained in:
Sam Brannen 2017-09-27 16:25:16 +02:00
parent 1a8122f97a
commit 550bed2905
1 changed files with 269 additions and 40 deletions

View File

@ -866,19 +866,20 @@ however, these lifecycle annotations have limited usage within an actual test cl
If a method within a test class is annotated with `@PostConstruct`, that method will be If a method within a test class is annotated with `@PostConstruct`, that method will be
executed before any __before__ methods of the underlying test framework (e.g., methods executed before any __before__ methods of the underlying test framework (e.g., methods
annotated with JUnit 4's `@Before`), and that will apply for every test method in the test annotated with JUnit Jupiter's `@BeforeEach`), and that will apply for every test method
class. On the other hand, if a method within a test class is annotated with in the test class. On the other hand, if a method within a test class is annotated with
`@PreDestroy`, that method will __never__ be executed. Within a test class it is `@PreDestroy`, that method will __never__ be executed. Within a test class it is
therefore recommended to use test lifecycle callbacks from the underlying test framework therefore recommended to use test lifecycle callbacks from the underlying test framework
instead of `@PostConstruct` and `@PreDestroy`. instead of `@PostConstruct` and `@PreDestroy`.
==== ====
[[integration-testing-annotations-junit]] [[integration-testing-annotations-junit4]]
==== Spring JUnit 4 Testing Annotations ==== Spring JUnit 4 Testing Annotations
The following annotations are __only__ supported when used in conjunction with the The following annotations are __only__ supported when used in conjunction with the
<<testcontext-junit4-runner,SpringRunner>>, <<testcontext-junit4-rules,Spring's JUnit <<testcontext-junit4-runner,SpringRunner>>, <<testcontext-junit4-rules,Spring's JUnit
rules>>, or <<testcontext-support-classes-junit4,Spring's JUnit 4 support classes>>. 4 rules>>, or <<testcontext-support-classes-junit4,Spring's JUnit 4 support classes>>.
===== @IfProfileValue ===== @IfProfileValue
`@IfProfileValue` indicates that the annotated test is enabled for a specific testing `@IfProfileValue` indicates that the annotated test is enabled for a specific testing
@ -974,6 +975,147 @@ well as any __set up__ or __tear down__ of the test fixture.
} }
---- ----
[[integration-testing-annotations-junit-jupiter]]
==== Spring JUnit Jupiter Testing Annotations
The following annotations are __only__ supported when used in conjunction with the
`SpringExtension` and JUnit Jupiter (i.e., the programming model in JUnit 5).
===== @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 annotated
classes may be declared via the `value` attribute in `@SpringJUnitConfig`.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
**@SpringJUnitConfig**(TestConfig.class)
class ConfigurationClassJUnitJupiterSpringTests {
// class body...
}
----
[source,java,indent=0]
[subs="verbatim,quotes"]
----
**@SpringJUnitConfig**(**locations** = "/test-config.xml")
class XmlJUnitJupiterSpringTests {
// class body...
}
----
See <<testcontext-ctx-management>> as well as the javadocs for `@SpringJUnitConfig` and
`@ContextConfiguration` for further details.
===== @SpringJUnitWebConfig
`@SpringJUnitWebConfig` is a _composed annotation_ that combines
`@ExtendWith(SpringExtension.class)` from JUnit Jupiter with `@ContextConfiguration` and
`@WebAppConfiguration` from the Spring TestContext Framework. It can be used 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 annotated classes may be declared via the `value`
attribute in `@SpringJUnitWebConfig`. In addition, the `value` attribute from
`@WebAppConfiguration` can only be overridden via the `resourcePath` attribute in
`@SpringJUnitWebConfig`.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
**@SpringJUnitWebConfig**(TestConfig.class)
class ConfigurationClassJUnitJupiterSpringWebTests {
// class body...
}
----
[source,java,indent=0]
[subs="verbatim,quotes"]
----
**@SpringJUnitWebConfig**(**locations** = "/test-config.xml")
class XmlJUnitJupiterSpringWebTests {
// class body...
}
----
See <<testcontext-ctx-management>> as well as the javadocs for `@SpringJUnitWebConfig`,
`@ContextConfiguration`, and `@WebAppConfiguration` for further details.
===== @EnabledIf
`@EnabledIf` is used to signal that the annotated JUnit Jupiter test class or test method
is _enabled_ and should be executed 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 will be __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.
* Spring Expression Language (SpEL) expression for example:
- `@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")`
* Placeholder for a property available in the Spring `Environment` for example:
- `@EnabledIf("${smoke.tests.enabled}")`
* Text literal for example:
- `@EnabledIf("true")`
Note, however, that a text literal which 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.
`@EnabledIf` may be used as a meta-annotation to create custom composed annotations. For
example, a custom `@EnabledOnMac` annotation can be created as follows.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@EnabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Enabled on Mac OS"
)
public @interface EnabledOnMac {}
----
===== @DisabledIf
`@DisabledIf` is used to signal that the annotated JUnit Jupiter test class or test
method is _disabled_ and should not be executed 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 will be __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.
* Spring Expression Language (SpEL) expression for example:
- `@DisabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")`
* Placeholder for a property available in the Spring `Environment` for example:
- `@DisabledIf("${smoke.tests.disabled}")`
* Text literal for example:
- `@DisabledIf("true")`
Note, however, that a text literal which 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.
`@DisabledIf` may be used as a meta-annotation to create custom composed annotations. For
example, a custom `@DisabledOnMac` annotation can be created as follows.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@DisabledIf(
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
reason = "Disabled on Mac OS"
)
public @interface DisabledOnMac {}
----
[[integration-testing-annotations-meta]] [[integration-testing-annotations-meta]]
==== Meta-Annotation Support for Testing ==== Meta-Annotation Support for Testing
@ -1000,13 +1142,17 @@ Each of the following may be used as meta-annotations in conjunction with the
* `@Sql` * `@Sql`
* `@SqlConfig` * `@SqlConfig`
* `@SqlGroup` * `@SqlGroup`
* `@Repeat` * `@Repeat` _(JUnit 4)_
* `@Timed` * `@Timed` _(JUnit 4)_
* `@IfProfileValue` * `@IfProfileValue` _(JUnit 4)_
* `@ProfileValueSourceConfiguration` * `@ProfileValueSourceConfiguration` _(JUnit 4)_
* `@SpringJUnitConfig` _(JUnit Jupiter)_
* `@SpringJUnitWebConfig` _(JUnit Jupiter)_
* `@EnabledIf` _(JUnit Jupiter)_
* `@DisabledIf` _(JUnit Jupiter)_
For example, if we discover that we are repeating the following configuration For example, if we discover that we are repeating the following configuration across our
across our JUnit 4 based test suite... _JUnit 4_ based test suite...
[source,java,indent=0] [source,java,indent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]
@ -1024,8 +1170,8 @@ across our JUnit 4 based test suite...
public class UserRepositoryTests { } public class UserRepositoryTests { }
---- ----
We can reduce the above duplication by introducing a custom _composed annotation_ We can reduce the above duplication by introducing a custom _composed annotation_ that
that centralizes the common test configuration like this: centralizes the common test configuration for Spring like this:
[source,java,indent=0] [source,java,indent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]
@ -1035,25 +1181,106 @@ that centralizes the common test configuration like this:
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"}) @ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev") @ActiveProfiles("dev")
@Transactional @Transactional
public @interface TransactionalDevTest { } public @interface TransactionalDevTestConfig { }
---- ----
Then we can use our custom `@TransactionalDevTest` annotation to simplify the Then we can use our custom `@TransactionalDevTestConfig` annotation to simplify the
configuration of individual test classes as follows: configuration of individual JUnit 4 based test classes as follows:
[source,java,indent=0] [source,java,indent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]
---- ----
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@TransactionalDevTest @TransactionalDevTestConfig
public class OrderRepositoryTests { } public class OrderRepositoryTests { }
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@TransactionalDevTest @TransactionalDevTestConfig
public class UserRepositoryTests { } public class UserRepositoryTests { }
---- ----
For further details, consult the <<core.adoc#annotation-programming-model,Spring Annotation Programming Model>>. If we are writing tests using JUnit Jupiter, we can reduce code duplication even further
since annotations in JUnit 5 can also be used as meta-annotations. For example, if we
discover that we are repeating the following configuration across our JUnit Jupiter based
test suite...
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@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 { }
----
We can reduce the above duplication by introducing a custom _composed annotation_
that centralizes the common test configuration for Spring and JUnit Jupiter like this:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface 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"]
----
@TransactionalDevTestConfig
class OrderRepositoryTests { }
@TransactionalDevTestConfig
class UserRepositoryTests { }
----
Since JUnit Jupiter supports the use of `@Test`, `@RepeatedTest`, `ParameterizedTest`,
etc. as meta-annotations, it is also possible to 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"]
----
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@Tag("integration-test") // org.junit.jupiter.api.Tag
@Test // org.junit.jupiter.api.Test
public @interface 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"]
----
@TransactionalIntegrationTest
void saveOrder() { }
@TransactionalIntegrationTest
void deleteOrder() { }
----
For further details, consult the <<core.adoc#annotation-programming-model,Spring
Annotation Programming Model>>.
[[testcontext-framework]] [[testcontext-framework]]
@ -1066,15 +1293,17 @@ configuration__ with reasonable defaults that can be overridden through annotati
configuration. configuration.
In addition to generic testing infrastructure, the TestContext framework provides In addition to generic testing infrastructure, the TestContext framework provides
explicit support for JUnit 4 and TestNG in the form of `abstract` support classes. For explicit support for JUnit 4, JUnit Jupiter (a.k.a., JUnit 5), and TestNG. For JUnit 4
JUnit 4, Spring also provides a custom JUnit `Runner` and custom JUnit `Rules` that allow and TestNG, Spring provides `abstract` support classes. Furthermore, Spring provides a
one to write so-called __POJO test classes__. POJO test classes are not required to custom JUnit `Runner` and custom JUnit `Rules` for _JUnit 4_ as well as a custom
extend a particular class hierarchy. `Extension` for _JUnit Jupiter_ that allow one to write so-called __POJO test classes__.
POJO test classes are not required to extend a particular class hierarchy such as the
`abstract` support classes.
The following section provides an overview of the internals of the TestContext The following section provides an overview of the internals of the TestContext framework.
framework. If you are only interested in _using_ the framework and not necessarily If you are only interested in _using_ the framework and not necessarily interested in
interested in _extending_ it with your own custom listeners or custom loaders, feel free _extending_ it with your own custom listeners or custom loaders, feel free to go directly
to go directly to the configuration (<<testcontext-ctx-management,context management>>, to the configuration (<<testcontext-ctx-management,context management>>,
<<testcontext-fixture-di,dependency injection>>, <<testcontext-tx,transaction <<testcontext-fixture-di,dependency injection>>, <<testcontext-tx,transaction
management>>), <<testcontext-support-classes,support classes>>, and management>>), <<testcontext-support-classes,support classes>>, and
<<integration-testing-annotations,annotation support>> sections. <<integration-testing-annotations,annotation support>> sections.
@ -1085,14 +1314,14 @@ management>>), <<testcontext-support-classes,support classes>>, and
The core of the framework consists of the `TestContextManager` class and the The core of the framework consists of the `TestContextManager` class and the
`TestContext`, `TestExecutionListener`, and `SmartContextLoader` interfaces. A `TestContext`, `TestExecutionListener`, and `SmartContextLoader` interfaces. A
`TestContextManager` is created per test class (e.g., for the execution of all test `TestContextManager` is created per test class (e.g., for the execution of all test
methods within a single test class in JUnit 4). The `TestContextManager` in turn manages a methods within a single test class in JUnit Jupiter). The `TestContextManager` in turn
`TestContext` that holds the context of the current test. The `TestContextManager` also manages a `TestContext` that holds the context of the current test. The
updates the state of the `TestContext` as the test progresses and delegates to `TestContextManager` also updates the state of the `TestContext` as the test progresses
`TestExecutionListener` implementations, which instrument the actual test execution by and delegates to `TestExecutionListener` implementations, which instrument the actual
providing dependency injection, managing transactions, and so on. A `SmartContextLoader` test execution by providing dependency injection, managing transactions, and so on. A
is responsible for loading an `ApplicationContext` for a given test class. Consult the `SmartContextLoader` is responsible for loading an `ApplicationContext` for a given test
javadocs and the Spring test suite for further information and examples of various class. Consult the javadocs and the Spring test suite for further information and
implementations. examples of various implementations.
===== TestContext ===== TestContext
`TestContext` encapsulates the context in which a test is executed, agnostic of the `TestContext` encapsulates the context in which a test is executed, agnostic of the
@ -3090,11 +3319,11 @@ transaction method__ or __after transaction method__ is executed at the appropri
[TIP] [TIP]
==== ====
Any __before methods__ (such as methods annotated with JUnit 4's `@Before`) and any __after Any __before methods__ (such as methods annotated with JUnit Jupiter's `@BeforeEach`) and
methods__ (such as methods annotated with JUnit 4's `@After`) are executed __within__ a any __after methods__ (such as methods annotated with JUnit Jupiter's `@AfterEach`) are
transaction. In addition, methods annotated with `@BeforeTransaction` or executed __within__ a transaction. In addition, methods annotated with
`@AfterTransaction` are naturally not executed for test methods that are not configured `@BeforeTransaction` or `@AfterTransaction` are naturally not executed for test methods
to run within a transaction. that are not configured to run within a transaction.
==== ====
[[testcontext-tx-mgr-config]] [[testcontext-tx-mgr-config]]
@ -3112,7 +3341,7 @@ used to look up a transaction manager in the test's `ApplicationContext`.
[[testcontext-tx-annotation-demo]] [[testcontext-tx-annotation-demo]]
===== Demonstration of all transaction-related annotations ===== Demonstration of all transaction-related annotations
The following JUnit 4 based example displays a fictitious integration testing scenario The following JUnit 4 based example displays a _fictitious_ integration testing scenario
highlighting all transaction-related annotations. The example is **not** intended to highlighting all transaction-related annotations. The example is **not** intended to
demonstrate best practices but rather to demonstrate how these annotations can be used. demonstrate best practices but rather to demonstrate how these annotations can be used.
Consult the <<integration-testing-annotations,annotation support>> section for further Consult the <<integration-testing-annotations,annotation support>> section for further