Skip to content

Commit 550bed2

Browse files
committed
Document JUnit Jupiter annotation support in the reference manual
Issue: SPR-14524
1 parent 1a8122f commit 550bed2

File tree

1 file changed

+271
-42
lines changed

1 file changed

+271
-42
lines changed

src/docs/asciidoc/testing.adoc

Lines changed: 271 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -866,19 +866,20 @@ however, these lifecycle annotations have limited usage within an actual test cl
866866
867867
If a method within a test class is annotated with `@PostConstruct`, that method will be
868868
executed before any __before__ methods of the underlying test framework (e.g., methods
869-
annotated with JUnit 4's `@Before`), and that will apply for every test method in the test
870-
class. On the other hand, if a method within a test class is annotated with
869+
annotated with JUnit Jupiter's `@BeforeEach`), and that will apply for every test method
870+
in the test class. On the other hand, if a method within a test class is annotated with
871871
`@PreDestroy`, that method will __never__ be executed. Within a test class it is
872872
therefore recommended to use test lifecycle callbacks from the underlying test framework
873873
instead of `@PostConstruct` and `@PreDestroy`.
874874
====
875875

876876

877-
[[integration-testing-annotations-junit]]
877+
[[integration-testing-annotations-junit4]]
878878
==== Spring JUnit 4 Testing Annotations
879+
879880
The following annotations are __only__ supported when used in conjunction with the
880881
<<testcontext-junit4-runner,SpringRunner>>, <<testcontext-junit4-rules,Spring's JUnit
881-
rules>>, or <<testcontext-support-classes-junit4,Spring's JUnit 4 support classes>>.
882+
4 rules>>, or <<testcontext-support-classes-junit4,Spring's JUnit 4 support classes>>.
882883

883884
===== @IfProfileValue
884885
`@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.
974975
}
975976
----
976977

978+
[[integration-testing-annotations-junit-jupiter]]
979+
==== Spring JUnit Jupiter Testing Annotations
980+
981+
The following annotations are __only__ supported when used in conjunction with the
982+
`SpringExtension` and JUnit Jupiter (i.e., the programming model in JUnit 5).
983+
984+
===== @SpringJUnitConfig
985+
986+
`@SpringJUnitConfig` is a _composed annotation_ that combines
987+
`@ExtendWith(SpringExtension.class)` from JUnit Jupiter with `@ContextConfiguration` from
988+
the Spring TestContext Framework. It can be used at the class level as a drop-in
989+
replacement for `@ContextConfiguration`. With regard to configuration options, the only
990+
difference between `@ContextConfiguration` and `@SpringJUnitConfig` is that annotated
991+
classes may be declared via the `value` attribute in `@SpringJUnitConfig`.
992+
993+
[source,java,indent=0]
994+
[subs="verbatim,quotes"]
995+
----
996+
**@SpringJUnitConfig**(TestConfig.class)
997+
class ConfigurationClassJUnitJupiterSpringTests {
998+
// class body...
999+
}
1000+
----
1001+
1002+
[source,java,indent=0]
1003+
[subs="verbatim,quotes"]
1004+
----
1005+
**@SpringJUnitConfig**(**locations** = "/test-config.xml")
1006+
class XmlJUnitJupiterSpringTests {
1007+
// class body...
1008+
}
1009+
----
1010+
1011+
See <<testcontext-ctx-management>> as well as the javadocs for `@SpringJUnitConfig` and
1012+
`@ContextConfiguration` for further details.
1013+
1014+
===== @SpringJUnitWebConfig
1015+
1016+
`@SpringJUnitWebConfig` is a _composed annotation_ that combines
1017+
`@ExtendWith(SpringExtension.class)` from JUnit Jupiter with `@ContextConfiguration` and
1018+
`@WebAppConfiguration` from the Spring TestContext Framework. It can be used at the class
1019+
level as a drop-in replacement for `@ContextConfiguration` and `@WebAppConfiguration`.
1020+
With regard to configuration options, the only difference between `@ContextConfiguration`
1021+
and `@SpringJUnitWebConfig` is that annotated classes may be declared via the `value`
1022+
attribute in `@SpringJUnitWebConfig`. In addition, the `value` attribute from
1023+
`@WebAppConfiguration` can only be overridden via the `resourcePath` attribute in
1024+
`@SpringJUnitWebConfig`.
1025+
1026+
[source,java,indent=0]
1027+
[subs="verbatim,quotes"]
1028+
----
1029+
**@SpringJUnitWebConfig**(TestConfig.class)
1030+
class ConfigurationClassJUnitJupiterSpringWebTests {
1031+
// class body...
1032+
}
1033+
----
1034+
1035+
[source,java,indent=0]
1036+
[subs="verbatim,quotes"]
1037+
----
1038+
**@SpringJUnitWebConfig**(**locations** = "/test-config.xml")
1039+
class XmlJUnitJupiterSpringWebTests {
1040+
// class body...
1041+
}
1042+
----
1043+
1044+
See <<testcontext-ctx-management>> as well as the javadocs for `@SpringJUnitWebConfig`,
1045+
`@ContextConfiguration`, and `@WebAppConfiguration` for further details.
1046+
1047+
===== @EnabledIf
1048+
1049+
`@EnabledIf` is used to signal that the annotated JUnit Jupiter test class or test method
1050+
is _enabled_ and should be executed if the supplied `expression` evaluates to `true`.
1051+
Specifically, if the expression evaluates to `Boolean.TRUE` or a `String` equal to
1052+
`"true"` (ignoring case), the test will be __enabled__. When applied at the class level,
1053+
all test methods within that class are automatically enabled by default as well.
1054+
1055+
Expressions can be any of the following.
1056+
1057+
* Spring Expression Language (SpEL) expression – for example:
1058+
- `@EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")`
1059+
* Placeholder for a property available in the Spring `Environment` – for example:
1060+
- `@EnabledIf("${smoke.tests.enabled}")`
1061+
* Text literal – for example:
1062+
- `@EnabledIf("true")`
1063+
1064+
Note, however, that a text literal which is _not_ the result of dynamic resolution of a
1065+
property placeholder is of zero practical value since `@EnabledIf("false")` is equivalent
1066+
to `@Disabled` and `@EnabledIf("true")` is logically meaningless.
1067+
1068+
`@EnabledIf` may be used as a meta-annotation to create custom composed annotations. For
1069+
example, a custom `@EnabledOnMac` annotation can be created as follows.
1070+
1071+
[source,java,indent=0]
1072+
[subs="verbatim,quotes"]
1073+
----
1074+
@Target({ ElementType.TYPE, ElementType.METHOD })
1075+
@Retention(RetentionPolicy.RUNTIME)
1076+
@EnabledIf(
1077+
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
1078+
reason = "Enabled on Mac OS"
1079+
)
1080+
public @interface EnabledOnMac {}
1081+
----
1082+
1083+
===== @DisabledIf
1084+
1085+
`@DisabledIf` is used to signal that the annotated JUnit Jupiter test class or test
1086+
method is _disabled_ and should not be executed if the supplied `expression` evaluates to
1087+
`true`. Specifically, if the expression evaluates to `Boolean.TRUE` or a `String` equal
1088+
to `"true"` (ignoring case), the test will be __disabled__. When applied at the class
1089+
level, all test methods within that class are automatically disabled as well.
1090+
1091+
Expressions can be any of the following.
1092+
1093+
* Spring Expression Language (SpEL) expression – for example:
1094+
- `@DisabledIf("#{systemProperties['os.name'].toLowerCase().contains('mac')}")`
1095+
* Placeholder for a property available in the Spring `Environment` – for example:
1096+
- `@DisabledIf("${smoke.tests.disabled}")`
1097+
* Text literal – for example:
1098+
- `@DisabledIf("true")`
1099+
1100+
Note, however, that a text literal which is _not_ the result of dynamic resolution of a
1101+
property placeholder is of zero practical value since `@DisabledIf("true")` is
1102+
equivalent to `@Disabled` and `@DisabledIf("false")` is logically meaningless.
1103+
1104+
`@DisabledIf` may be used as a meta-annotation to create custom composed annotations. For
1105+
example, a custom `@DisabledOnMac` annotation can be created as follows.
1106+
1107+
[source,java,indent=0]
1108+
[subs="verbatim,quotes"]
1109+
----
1110+
@Target({ ElementType.TYPE, ElementType.METHOD })
1111+
@Retention(RetentionPolicy.RUNTIME)
1112+
@DisabledIf(
1113+
expression = "#{systemProperties['os.name'].toLowerCase().contains('mac')}",
1114+
reason = "Disabled on Mac OS"
1115+
)
1116+
public @interface DisabledOnMac {}
1117+
----
1118+
9771119

9781120
[[integration-testing-annotations-meta]]
9791121
==== Meta-Annotation Support for Testing
@@ -1000,13 +1142,17 @@ Each of the following may be used as meta-annotations in conjunction with the
10001142
* `@Sql`
10011143
* `@SqlConfig`
10021144
* `@SqlGroup`
1003-
* `@Repeat`
1004-
* `@Timed`
1005-
* `@IfProfileValue`
1006-
* `@ProfileValueSourceConfiguration`
1007-
1008-
For example, if we discover that we are repeating the following configuration
1009-
across our JUnit 4 based test suite...
1145+
* `@Repeat` _(JUnit 4)_
1146+
* `@Timed` _(JUnit 4)_
1147+
* `@IfProfileValue` _(JUnit 4)_
1148+
* `@ProfileValueSourceConfiguration` _(JUnit 4)_
1149+
* `@SpringJUnitConfig` _(JUnit Jupiter)_
1150+
* `@SpringJUnitWebConfig` _(JUnit Jupiter)_
1151+
* `@EnabledIf` _(JUnit Jupiter)_
1152+
* `@DisabledIf` _(JUnit Jupiter)_
1153+
1154+
For example, if we discover that we are repeating the following configuration across our
1155+
_JUnit 4_ based test suite...
10101156

10111157
[source,java,indent=0]
10121158
[subs="verbatim,quotes"]
@@ -1024,8 +1170,8 @@ across our JUnit 4 based test suite...
10241170
public class UserRepositoryTests { }
10251171
----
10261172

1027-
We can reduce the above duplication by introducing a custom _composed annotation_
1028-
that centralizes the common test configuration like this:
1173+
We can reduce the above duplication by introducing a custom _composed annotation_ that
1174+
centralizes the common test configuration for Spring like this:
10291175

10301176
[source,java,indent=0]
10311177
[subs="verbatim,quotes"]
@@ -1035,25 +1181,106 @@ that centralizes the common test configuration like this:
10351181
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
10361182
@ActiveProfiles("dev")
10371183
@Transactional
1038-
public @interface TransactionalDevTest { }
1184+
public @interface TransactionalDevTestConfig { }
10391185
----
10401186

1041-
Then we can use our custom `@TransactionalDevTest` annotation to simplify the
1042-
configuration of individual test classes as follows:
1187+
Then we can use our custom `@TransactionalDevTestConfig` annotation to simplify the
1188+
configuration of individual JUnit 4 based test classes as follows:
10431189

10441190
[source,java,indent=0]
10451191
[subs="verbatim,quotes"]
10461192
----
10471193
@RunWith(SpringRunner.class)
1048-
@TransactionalDevTest
1194+
@TransactionalDevTestConfig
10491195
public class OrderRepositoryTests { }
10501196
10511197
@RunWith(SpringRunner.class)
1052-
@TransactionalDevTest
1198+
@TransactionalDevTestConfig
10531199
public class UserRepositoryTests { }
10541200
----
10551201

1056-
For further details, consult the <<core.adoc#annotation-programming-model,Spring Annotation Programming Model>>.
1202+
If we are writing tests using JUnit Jupiter, we can reduce code duplication even further
1203+
since annotations in JUnit 5 can also be used as meta-annotations. For example, if we
1204+
discover that we are repeating the following configuration across our JUnit Jupiter based
1205+
test suite...
1206+
1207+
[source,java,indent=0]
1208+
[subs="verbatim,quotes"]
1209+
----
1210+
@ExtendWith(SpringExtension.class)
1211+
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
1212+
@ActiveProfiles("dev")
1213+
@Transactional
1214+
class OrderRepositoryTests { }
1215+
1216+
@ExtendWith(SpringExtension.class)
1217+
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
1218+
@ActiveProfiles("dev")
1219+
@Transactional
1220+
class UserRepositoryTests { }
1221+
----
1222+
1223+
We can reduce the above duplication by introducing a custom _composed annotation_
1224+
that centralizes the common test configuration for Spring and JUnit Jupiter like this:
1225+
1226+
[source,java,indent=0]
1227+
[subs="verbatim,quotes"]
1228+
----
1229+
@Target(ElementType.TYPE)
1230+
@Retention(RetentionPolicy.RUNTIME)
1231+
@ExtendWith(SpringExtension.class)
1232+
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
1233+
@ActiveProfiles("dev")
1234+
@Transactional
1235+
public @interface TransactionalDevTestConfig { }
1236+
----
1237+
1238+
Then we can use our custom `@TransactionalDevTestConfig` annotation to simplify the
1239+
configuration of individual JUnit Jupiter based test classes as follows:
1240+
1241+
[source,java,indent=0]
1242+
[subs="verbatim,quotes"]
1243+
----
1244+
@TransactionalDevTestConfig
1245+
class OrderRepositoryTests { }
1246+
1247+
@TransactionalDevTestConfig
1248+
class UserRepositoryTests { }
1249+
----
1250+
1251+
Since JUnit Jupiter supports the use of `@Test`, `@RepeatedTest`, `ParameterizedTest`,
1252+
etc. as meta-annotations, it is also possible to create custom composed annotations at
1253+
the test method level. For example, if we wish to create a _composed annotation_ that
1254+
combines the `@Test` and `@Tag` annotations from JUnit Jupiter with the `@Transactional`
1255+
annotation from Spring, we could create an `@TransactionalIntegrationTest` annotation as
1256+
follows.
1257+
1258+
[source,java,indent=0]
1259+
[subs="verbatim,quotes"]
1260+
----
1261+
@Target(ElementType.METHOD)
1262+
@Retention(RetentionPolicy.RUNTIME)
1263+
@Transactional
1264+
@Tag("integration-test") // org.junit.jupiter.api.Tag
1265+
@Test // org.junit.jupiter.api.Test
1266+
public @interface TransactionalIntegrationTest { }
1267+
----
1268+
1269+
Then we can use our custom `@TransactionalIntegrationTest` annotation to simplify the
1270+
configuration of individual JUnit Jupiter based test methods as follows:
1271+
1272+
[source,java,indent=0]
1273+
[subs="verbatim,quotes"]
1274+
----
1275+
@TransactionalIntegrationTest
1276+
void saveOrder() { }
1277+
1278+
@TransactionalIntegrationTest
1279+
void deleteOrder() { }
1280+
----
1281+
1282+
For further details, consult the <<core.adoc#annotation-programming-model,Spring
1283+
Annotation Programming Model>>.
10571284

10581285

10591286
[[testcontext-framework]]
@@ -1066,15 +1293,17 @@ configuration__ with reasonable defaults that can be overridden through annotati
10661293
configuration.
10671294

10681295
In addition to generic testing infrastructure, the TestContext framework provides
1069-
explicit support for JUnit 4 and TestNG in the form of `abstract` support classes. For
1070-
JUnit 4, Spring also provides a custom JUnit `Runner` and custom JUnit `Rules` that allow
1071-
one to write so-called __POJO test classes__. POJO test classes are not required to
1072-
extend a particular class hierarchy.
1073-
1074-
The following section provides an overview of the internals of the TestContext
1075-
framework. If you are only interested in _using_ the framework and not necessarily
1076-
interested in _extending_ it with your own custom listeners or custom loaders, feel free
1077-
to go directly to the configuration (<<testcontext-ctx-management,context management>>,
1296+
explicit support for JUnit 4, JUnit Jupiter (a.k.a., JUnit 5), and TestNG. For JUnit 4
1297+
and TestNG, Spring provides `abstract` support classes. Furthermore, Spring provides a
1298+
custom JUnit `Runner` and custom JUnit `Rules` for _JUnit 4_ as well as a custom
1299+
`Extension` for _JUnit Jupiter_ that allow one to write so-called __POJO test classes__.
1300+
POJO test classes are not required to extend a particular class hierarchy such as the
1301+
`abstract` support classes.
1302+
1303+
The following section provides an overview of the internals of the TestContext framework.
1304+
If you are only interested in _using_ the framework and not necessarily interested in
1305+
_extending_ it with your own custom listeners or custom loaders, feel free to go directly
1306+
to the configuration (<<testcontext-ctx-management,context management>>,
10781307
<<testcontext-fixture-di,dependency injection>>, <<testcontext-tx,transaction
10791308
management>>), <<testcontext-support-classes,support classes>>, and
10801309
<<integration-testing-annotations,annotation support>> sections.
@@ -1085,14 +1314,14 @@ management>>), <<testcontext-support-classes,support classes>>, and
10851314
The core of the framework consists of the `TestContextManager` class and the
10861315
`TestContext`, `TestExecutionListener`, and `SmartContextLoader` interfaces. A
10871316
`TestContextManager` is created per test class (e.g., for the execution of all test
1088-
methods within a single test class in JUnit 4). The `TestContextManager` in turn manages a
1089-
`TestContext` that holds the context of the current test. The `TestContextManager` also
1090-
updates the state of the `TestContext` as the test progresses and delegates to
1091-
`TestExecutionListener` implementations, which instrument the actual test execution by
1092-
providing dependency injection, managing transactions, and so on. A `SmartContextLoader`
1093-
is responsible for loading an `ApplicationContext` for a given test class. Consult the
1094-
javadocs and the Spring test suite for further information and examples of various
1095-
implementations.
1317+
methods within a single test class in JUnit Jupiter). The `TestContextManager` in turn
1318+
manages a `TestContext` that holds the context of the current test. The
1319+
`TestContextManager` also updates the state of the `TestContext` as the test progresses
1320+
and delegates to `TestExecutionListener` implementations, which instrument the actual
1321+
test execution by providing dependency injection, managing transactions, and so on. A
1322+
`SmartContextLoader` is responsible for loading an `ApplicationContext` for a given test
1323+
class. Consult the javadocs and the Spring test suite for further information and
1324+
examples of various implementations.
10961325

10971326
===== TestContext
10981327
`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
30903319

30913320
[TIP]
30923321
====
3093-
Any __before methods__ (such as methods annotated with JUnit 4's `@Before`) and any __after
3094-
methods__ (such as methods annotated with JUnit 4's `@After`) are executed __within__ a
3095-
transaction. In addition, methods annotated with `@BeforeTransaction` or
3096-
`@AfterTransaction` are naturally not executed for test methods that are not configured
3097-
to run within a transaction.
3322+
Any __before methods__ (such as methods annotated with JUnit Jupiter's `@BeforeEach`) and
3323+
any __after methods__ (such as methods annotated with JUnit Jupiter's `@AfterEach`) are
3324+
executed __within__ a transaction. In addition, methods annotated with
3325+
`@BeforeTransaction` or `@AfterTransaction` are naturally not executed for test methods
3326+
that are not configured to run within a transaction.
30983327
====
30993328

31003329
[[testcontext-tx-mgr-config]]
@@ -3112,7 +3341,7 @@ used to look up a transaction manager in the test's `ApplicationContext`.
31123341
[[testcontext-tx-annotation-demo]]
31133342
===== Demonstration of all transaction-related annotations
31143343

3115-
The following JUnit 4 based example displays a fictitious integration testing scenario
3344+
The following JUnit 4 based example displays a _fictitious_ integration testing scenario
31163345
highlighting all transaction-related annotations. The example is **not** intended to
31173346
demonstrate best practices but rather to demonstrate how these annotations can be used.
31183347
Consult the <<integration-testing-annotations,annotation support>> section for further

0 commit comments

Comments
 (0)