Migrate to Asciidoctor Tabs

This commit is contained in:
Rob Winch
2023-04-20 16:21:36 -05:00
committed by rstoyanchev
parent 71154fd16b
commit 39146f9066
243 changed files with 7124 additions and 1779 deletions

View File

@@ -25,14 +25,18 @@ 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:
[tabs]
======
Java::
+
[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"]
@@ -49,14 +53,18 @@ configuration class:
The following example shows how to use the `@SpringJUnitConfig` annotation to specify the
location of a configuration file:
[tabs]
======
Java::
+
[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"]
@@ -90,14 +98,18 @@ attribute from `@WebAppConfiguration` only by using the `resourcePath` attribute
The following example shows how to use the `@SpringJUnitWebConfig` annotation to specify
a configuration class:
[tabs]
======
Java::
+
[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"]
@@ -114,14 +126,18 @@ a configuration class:
The following example shows how to use the `@SpringJUnitWebConfig` annotation to specify the
location of a configuration file:
[tabs]
======
Java::
+
[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"]
@@ -248,8 +264,11 @@ 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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@@ -259,8 +278,10 @@ example, you can create a custom `@EnabledOnMac` annotation as follows:
)
public @interface EnabledOnMac {}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@@ -270,6 +291,7 @@ example, you can create a custom `@EnabledOnMac` annotation as follows:
)
annotation class EnabledOnMac {}
----
======
[NOTE]
====
@@ -308,8 +330,11 @@ 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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@@ -320,8 +345,9 @@ example, you can create a custom `@DisabledOnMac` annotation as follows:
public @interface DisabledOnMac {}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@@ -331,6 +357,7 @@ example, you can create a custom `@DisabledOnMac` annotation as follows:
)
annotation class DisabledOnMac {}
----
======
[NOTE]
====

View File

@@ -27,8 +27,11 @@ means the test is implicitly enabled. This is analogous to the semantics of JUni
The following example shows a test that has an `@IfProfileValue` annotation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@IfProfileValue(name="java.vendor", value="Oracle Corporation") // <1>
@Test
@@ -36,6 +39,7 @@ The following example shows a test that has an `@IfProfileValue` annotation:
// 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"]
@@ -54,8 +58,11 @@ Alternatively, you can configure `@IfProfileValue` with a list of `values` (with
semantics) to achieve TestNG-like support for test groups in a JUnit 4 environment.
Consider the following example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"}) // <1>
@Test
@@ -63,6 +70,7 @@ Consider the following example:
// 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"]
@@ -86,14 +94,18 @@ of `ProfileValueSource` to use when retrieving profile values configured through
test, `SystemProfileValueSource` is used by default. The following example shows how to
use `@ProfileValueSourceConfiguration`:
[tabs]
======
Java::
+
[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"]
@@ -118,14 +130,18 @@ The time period includes running the test method itself, any repetitions of the
`@Repeat`), as well as any setting up or tearing down of the test fixture. The following
example shows how to use it:
[tabs]
======
Java::
+
[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"]
@@ -158,8 +174,11 @@ xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit4-rules
preparation of the test instance by `TestExecutionListener` implementations. The
following example shows how to use the `@Repeat` annotation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Repeat(10) // <1>
@Test
@@ -167,6 +186,7 @@ following example shows how to use the `@Repeat` annotation:
// ...
}
----
======
<1> Repeat this test ten times.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -38,8 +38,11 @@ xref:testing/testcontext-framework.adoc[TestContext framework].
Consider the following example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RunWith(SpringRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@@ -54,8 +57,9 @@ Consider the following example:
public class UserRepositoryTests { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RunWith(SpringRunner::class)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@@ -69,13 +73,17 @@ Consider the following example:
@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@@ -85,8 +93,9 @@ that centralizes the common test configuration for Spring, as follows:
public @interface TransactionalDevTestConfig { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@@ -95,12 +104,16 @@ that centralizes the common test configuration for Spring, as follows:
@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RunWith(SpringRunner.class)
@TransactionalDevTestConfig
@@ -111,8 +124,9 @@ configuration of individual JUnit 4 based test classes, as follows:
public class UserRepositoryTests { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RunWith(SpringRunner::class)
@TransactionalDevTestConfig
@@ -122,13 +136,17 @@ configuration of individual JUnit 4 based test classes, as follows:
@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@@ -142,8 +160,10 @@ example:
@Transactional
class UserRepositoryTests { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@ContextConfiguration("/app-config.xml", "/test-data-access-config.xml")
@@ -157,14 +177,18 @@ example:
@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@@ -174,8 +198,10 @@ as follows:
@Transactional
public @interface TransactionalDevTestConfig { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@@ -185,12 +211,16 @@ as follows:
@Transactional
annotation class TransactionalDevTestConfig { }
----
======
Then we can use our custom `@TransactionalDevTestConfig` annotation to simplify the
configuration of individual JUnit Jupiter based test classes, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@TransactionalDevTestConfig
class OrderRepositoryTests { }
@@ -198,8 +228,10 @@ configuration of individual JUnit Jupiter based test classes, as follows:
@TransactionalDevTestConfig
class UserRepositoryTests { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@TransactionalDevTestConfig
class OrderRepositoryTests { }
@@ -207,6 +239,7 @@ configuration of individual JUnit Jupiter based test classes, as follows:
@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
@@ -215,8 +248,11 @@ the `@Test` and `@Tag` annotations from JUnit Jupiter with the `@Transactional`
annotation from Spring, we could create an `@TransactionalIntegrationTest` annotation, as
follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@@ -225,8 +261,10 @@ follows:
@Test // org.junit.jupiter.api.Test
public @interface TransactionalIntegrationTest { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
@@ -235,12 +273,16 @@ follows:
@Test // org.junit.jupiter.api.Test
annotation class TransactionalIntegrationTest { }
----
======
Then we can use our custom `@TransactionalIntegrationTest` annotation to simplify the
configuration of individual JUnit Jupiter based test methods, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@TransactionalIntegrationTest
void saveOrder() { }
@@ -249,8 +291,9 @@ configuration of individual JUnit Jupiter based test methods, as follows:
void deleteOrder() { }
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@TransactionalIntegrationTest
fun saveOrder() { }
@@ -258,6 +301,7 @@ configuration of individual JUnit Jupiter based test methods, as follows:
@TransactionalIntegrationTest
fun deleteOrder() { }
----
======
For further details, see the
https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model[Spring Annotation Programming Model]

View File

@@ -7,8 +7,11 @@ integration test.
The following example indicates that the `dev` profile should be active:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@ActiveProfiles("dev") // <1>
@@ -16,6 +19,7 @@ The following example indicates that the `dev` profile should be active:
// class body...
}
----
======
<1> Indicate that the `dev` profile should be active.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -33,8 +37,11 @@ The following example indicates that the `dev` profile should be active:
The following example indicates that both the `dev` and the `integration` profiles should
be active:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@ActiveProfiles({"dev", "integration"}) // <1>
@@ -42,6 +49,7 @@ be active:
// class body...
}
----
======
<1> Indicate that the `dev` and `integration` profiles should be active.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -7,14 +7,18 @@ transaction by using Spring's `@Transactional` annotation. `@AfterTransaction` m
are not required to be `public` and may be declared on Java 8-based interface default
methods.
[tabs]
======
Java::
+
[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"]

View File

@@ -9,14 +9,18 @@ methods.
The following example shows how to use the `@BeforeTransaction` annotation:
[tabs]
======
Java::
+
[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"]

View File

@@ -9,8 +9,11 @@ annotation.
The following example shows how to use the `@Commit` annotation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Commit // <1>
@Test
@@ -18,6 +21,7 @@ The following example shows how to use the `@Commit` annotation:
// ...
}
----
======
<1> Commit the result of the test to the database.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -15,14 +15,18 @@ xref:testing/testcontext-framework/ctx-management/javaconfig.adoc#testcontext-ct
The following example shows a `@ContextConfiguration` annotation that refers to an XML
file:
[tabs]
======
Java::
+
[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"]
@@ -38,14 +42,18 @@ file:
The following example shows a `@ContextConfiguration` annotation that refers to a class:
[tabs]
======
Java::
+
[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"]
@@ -63,14 +71,18 @@ As an alternative or in addition to declaring resource locations or component cl
you can use `@ContextConfiguration` to declare `ApplicationContextInitializer` classes.
The following example shows such a case:
[tabs]
======
Java::
+
[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"]
@@ -91,14 +103,18 @@ component `classes`.
The following example uses both a location and a loader:
[tabs]
======
Java::
+
[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"]

View File

@@ -8,8 +8,11 @@ defines a level in the context hierarchy. The following examples demonstrate the
`@ContextHierarchy` within a single test class (`@ContextHierarchy` can also be used
within a test class hierarchy):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@@ -19,8 +22,10 @@ within a test class hierarchy):
// class body...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextHierarchy(
ContextConfiguration("/parent-config.xml"),
@@ -29,9 +34,13 @@ within a test class hierarchy):
// class body...
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@WebAppConfiguration
@ContextHierarchy({
@@ -42,8 +51,10 @@ within a test class hierarchy):
// class body...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@WebAppConfiguration
@ContextHierarchy(
@@ -53,6 +64,7 @@ within a test class hierarchy):
// 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

View File

@@ -20,14 +20,18 @@ configuration scenarios:
* Before the current test class, when declared on a class with class mode set to
`BEFORE_CLASS`.
+
[tabs]
======
Java::
+
[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"]
@@ -43,14 +47,18 @@ configuration scenarios:
* After the current test class, when declared on a class with class mode set to
`AFTER_CLASS` (i.e., the default class mode).
+
[tabs]
======
Java::
+
[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"]
@@ -67,14 +75,18 @@ configuration scenarios:
* Before each test method in the current test class, when declared on a class with class
mode set to `BEFORE_EACH_TEST_METHOD.`
+
[tabs]
======
Java::
+
[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"]
@@ -91,14 +103,18 @@ mode set to `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.`
+
[tabs]
======
Java::
+
[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"]
@@ -115,8 +131,11 @@ mode set to `AFTER_EACH_TEST_METHOD.`
* Before the current test, when declared on a method with the method mode set to
`BEFORE_METHOD`.
+
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext(methodMode = BEFORE_METHOD) // <1>
@Test
@@ -124,6 +143,7 @@ mode set to `AFTER_EACH_TEST_METHOD.`
// 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"]
@@ -140,8 +160,11 @@ mode set to `AFTER_EACH_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).
+
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@DirtiesContext // <1>
@Test
@@ -149,6 +172,7 @@ mode set to `AFTER_EACH_TEST_METHOD.`
// 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"]
@@ -173,8 +197,11 @@ context are removed from the context cache and closed. If the exhaustive algorit
overkill for a particular use case, you can specify the simpler current level algorithm,
as the following example shows.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextHierarchy({
@ContextConfiguration("/parent-config.xml"),
@@ -193,6 +220,7 @@ as the following example shows.
}
}
----
======
<1> Use the current-level algorithm.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -10,8 +10,11 @@ https://www.testcontainers.org/[Testcontainers] project.
The following example demonstrates how to register a dynamic property:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
class MyIntegrationTests {
@@ -26,6 +29,7 @@ The following example demonstrates how to register a dynamic property:
// 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.

View File

@@ -15,8 +15,11 @@ 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):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Rollback(false) // <1>
@Test
@@ -24,6 +27,7 @@ result is committed to the database):
// ...
}
----
======
<1> Do not roll back the result.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -5,8 +5,11 @@
against a given database during integration tests. The following example shows how to use
it:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"}) // <1>
@@ -14,6 +17,7 @@ it:
// 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"]

View File

@@ -4,8 +4,11 @@
`@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:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@Sql(
@@ -16,6 +19,7 @@ configured with the `@Sql` annotation. The following example shows how to use it
// 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"]

View File

@@ -7,8 +7,11 @@ in conjunction with Java 8's support for repeatable annotations, where `@Sql` ca
declared several times on the same class or method, implicitly generating this container
annotation. The following example shows how to declare an SQL group:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@SqlGroup({ // <1>
@@ -19,6 +22,7 @@ annotation. The following example shows how to declare an SQL group:
// 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"]

View File

@@ -11,8 +11,11 @@ Note that a method-level `@SqlMergeMode` declaration overrides a class-level dec
The following example shows how to use `@SqlMergeMode` at the class level.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
@@ -26,6 +29,7 @@ The following example shows how to use `@SqlMergeMode` at the class level.
}
}
----
======
<1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -47,8 +51,11 @@ The following example shows how to use `@SqlMergeMode` at the class level.
The following example shows how to use `@SqlMergeMode` at the method level.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
@Sql("/test-schema.sql")
@@ -62,6 +69,7 @@ The following example shows how to use `@SqlMergeMode` at the method level.
}
}
----
======
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -8,8 +8,11 @@ xref:testing/testcontext-framework/tel-config.adoc[`TestExecutionListener` Confi
The following example shows how to register two `TestExecutionListener` implementations:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class}) // <1>
@@ -17,6 +20,7 @@ The following example shows how to register two `TestExecutionListener` implemen
// class body...
}
----
======
<1> Register two `TestExecutionListener` implementations.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -8,8 +8,11 @@ integration test.
The following example demonstrates how to declare a properties file from the classpath:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestPropertySource("/test.properties") // <1>
@@ -17,6 +20,7 @@ The following example demonstrates how to declare a properties file from the cla
// class body...
}
----
======
<1> Get properties from `test.properties` in the root of the classpath.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -33,8 +37,11 @@ The following example demonstrates how to declare a properties file from the cla
The following example demonstrates how to declare inlined properties:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestPropertySource(properties = { "timezone = GMT", "port: 4242" }) // <1>
@@ -42,6 +49,7 @@ The following example demonstrates how to declare inlined properties:
// class body...
}
----
======
<1> Declare `timezone` and `port` properties.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -13,8 +13,11 @@ resource base path). The resource base path is used behind the scenes to create
The following example shows how to use the `@WebAppConfiguration` annotation:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@WebAppConfiguration // <1>
@@ -22,6 +25,7 @@ The following example shows how to use the `@WebAppConfiguration` annotation:
// class body...
}
----
======
<1> The `@WebAppConfiguration` annotation.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -43,8 +47,11 @@ supported. If no resource prefix is supplied, the path is assumed to be a file s
resource. The following example shows how to specify a classpath resource:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@WebAppConfiguration("classpath:test-web-resources") // <1>
@@ -52,6 +59,7 @@ resource. The following example shows how to specify a classpath resource:
// class body...
}
----
======
<1> Specifying a classpath resource.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -6,8 +6,11 @@ idea is to declare expected requests and to provide "`stub`" responses so that y
focus on testing the code in isolation (that is, without running a server). The following
example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
RestTemplate restTemplate = new RestTemplate();
@@ -18,8 +21,10 @@ example shows how to do so:
mockServer.verify();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val restTemplate = RestTemplate()
@@ -30,6 +35,7 @@ example shows how to do so:
mockServer.verify()
----
======
In the preceding example, `MockRestServiceServer` (the central class for client-side REST
tests) configures the `RestTemplate` with a custom `ClientHttpRequestFactory` that
@@ -45,24 +51,33 @@ can set the `ignoreExpectOrder` option when building the server, in which case a
expectations are checked (in order) to find a match for a given request. That means
requests are allowed to come in any order. The following example uses `ignoreExpectOrder`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
----
======
Even with unordered requests by default, each request is allowed to run once only.
The `expect` method provides an overloaded variant that accepts an `ExpectedCount`
argument that specifies a count range (for example, `once`, `manyTimes`, `max`, `min`,
`between`, and so on). The following example uses `times`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
RestTemplate restTemplate = new RestTemplate();
@@ -74,8 +89,10 @@ argument that specifies a count range (for example, `once`, `manyTimes`, `max`,
mockServer.verify();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val restTemplate = RestTemplate()
@@ -87,6 +104,7 @@ argument that specifies a count range (for example, `once`, `manyTimes`, `max`,
mockServer.verify()
----
======
Note that, when `ignoreExpectOrder` is not set (the default), and, therefore, requests
are expected in order of declaration, then that order applies only to the first of any
@@ -100,29 +118,38 @@ As an alternative to all of the above, the client-side test support also provide
bind it to a `MockMvc` instance. That allows processing requests using actual server-side
logic but without running a server. The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.restTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(mockMvc));
// Test code that uses the above RestTemplate ...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build()
restTemplate = RestTemplate(MockMvcClientHttpRequestFactory(mockMvc))
// Test code that uses the above RestTemplate ...
----
======
In some cases it may be necessary to perform an actual call to a remote service instead
of mocking the response. The following example shows how to do that through
`ExecutingResponseCreator`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
RestTemplate restTemplate = new RestTemplate();
@@ -137,8 +164,10 @@ of mocking the response. The following example shows how to do that through
mockServer.verify();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val restTemplate = RestTemplate()
@@ -153,6 +182,7 @@ of mocking the response. The following example shows how to do that through
mockServer.verify()
----
======
In the preceding example, we create the `ExecutingResponseCreator` using the
`ClientHttpRequestFactory` from the `RestTemplate` _before_ `MockRestServiceServer` replaces

View File

@@ -16,8 +16,11 @@ first, then manually performing the async dispatch, and finally verifying the re
Below is an example test for controller methods that return `DeferredResult`, `Callable`,
or reactive type such as Reactor `Mono`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// static import of MockMvcRequestBuilders.* and MockMvcResultMatchers.*
@@ -34,6 +37,7 @@ or reactive type such as Reactor `Mono`:
.andExpect(content().string("body"));
}
----
======
<1> Check response status is still unchanged
<2> Async processing must have started
<3> Wait and assert the async result

View File

@@ -5,16 +5,20 @@ You can define expectations by appending one or more `andExpect(..)` calls after
performing a request, as the following example shows. As soon as one expectation fails,
no other expectations will be asserted.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// static import of MockMvcRequestBuilders.* and MockMvcResultMatchers.*
mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.get
@@ -22,14 +26,18 @@ no other expectations will be asserted.
status { isOk() }
}
----
======
You can define multiple expectations by appending `andExpectAll(..)` after performing a
request, as the following example shows. In contrast to `andExpect(..)`,
`andExpectAll(..)` guarantees that all supplied expectations will be asserted and that
all failures will be tracked and reported.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// static import of MockMvcRequestBuilders.* and MockMvcResultMatchers.*
@@ -38,8 +46,9 @@ all failures will be tracked and reported.
content().contentType("application/json;charset=UTF-8"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.get
@@ -48,6 +57,7 @@ all failures will be tracked and reported.
content { contentType(APPLICATION_JSON) }
}
----
======
`MockMvcResultMatchers.*` provides a number of expectations, some of which are further
nested with more detailed expectations.
@@ -64,16 +74,20 @@ inspect Servlet specific aspects, such as request and session attributes.
The following test asserts that binding or validation failed:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(post("/persons"))
.andExpect(status().isOk())
.andExpect(model().attributeHasErrors("person"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.post
@@ -84,13 +98,17 @@ The following test asserts that binding or validation failed:
}
}
----
======
Many times, when writing tests, it is useful to dump the results of the performed
request. You can do so as follows, where `print()` is a static import from
`MockMvcResultHandlers`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(post("/persons"))
.andDo(print())
@@ -98,8 +116,9 @@ request. You can do so as follows, where `print()` is a static import from
.andExpect(model().attributeHasErrors("person"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.post
@@ -112,6 +131,7 @@ request. You can do so as follows, where `print()` is a static import from
}
}
----
======
As long as request processing does not cause an unhandled exception, the `print()` method
prints all the available result data to `System.out`. There is also a `log()` method and
@@ -126,36 +146,47 @@ In some cases, you may want to get direct access to the result and verify someth
cannot be verified otherwise. This can be achieved by appending `.andReturn()` after all
other expectations, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk()).andReturn();
// ...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
var mvcResult = mockMvc.post("/persons").andExpect { status { isOk() } }.andReturn()
// ...
----
======
If all tests repeat the same expectations, you can set up common expectations once when
building the `MockMvc` instance, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
standaloneSetup(new SimpleController())
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType("application/json;charset=UTF-8"))
.build()
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed
----
======
Note that common expectations are always applied and cannot be overridden without
creating a separate `MockMvc` instance.
@@ -164,15 +195,19 @@ When a JSON response content contains hypermedia links created with
https://github.com/spring-projects/spring-hateoas[Spring HATEOAS], you can verify the
resulting links by using JsonPath expressions, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(get("/people").accept(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.links[?(@.rel == 'self')].href").value("http://localhost:8080/people"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
mockMvc.get("/people") {
accept(MediaType.APPLICATION_JSON)
@@ -182,21 +217,26 @@ resulting links by using JsonPath expressions, as the following example shows:
}
}
----
======
When XML response content contains hypermedia links created with
https://github.com/spring-projects/spring-hateoas[Spring HATEOAS], you can verify the
resulting links by using XPath expressions:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
Map<String, String> ns = Collections.singletonMap("ns", "http://www.w3.org/2005/Atom");
mockMvc.perform(get("/handle").accept(MediaType.APPLICATION_XML))
.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val ns = mapOf("ns" to "http://www.w3.org/2005/Atom")
mockMvc.get("/handle") {
@@ -207,4 +247,5 @@ resulting links by using XPath expressions:
}
}
----
======

View File

@@ -5,16 +5,22 @@
When setting up a `MockMvc` instance, you can register one or more Servlet `Filter`
instances, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed
----
======
Registered filters are invoked through the `MockFilterChain` from `spring-test`, and the
last filter delegates to the `DispatcherServlet`.

View File

@@ -14,8 +14,11 @@ First, make sure that you have included a test dependency on
We can easily create an HtmlUnit `WebClient` that integrates with MockMvc by using the
`MockMvcWebClientBuilder`, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebClient webClient;
@@ -27,8 +30,9 @@ We can easily create an HtmlUnit `WebClient` that integrates with MockMvc by usi
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
lateinit var webClient: WebClient
@@ -39,6 +43,7 @@ We can easily create an HtmlUnit `WebClient` that integrates with MockMvc by usi
.build()
}
----
======
NOTE: This is a simple example of using `MockMvcWebClientBuilder`. For advanced usage,
see xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced `MockMvcWebClientBuilder`].
@@ -55,17 +60,22 @@ Now we can use HtmlUnit as we normally would but without the need to deploy our
application to a Servlet container. For example, we can request the view to create a
message with the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
HtmlPage createMsgFormPage = webClient.getPage("http://localhost/messages/form");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val createMsgFormPage = webClient.getPage("http://localhost/messages/form")
----
======
NOTE: The default context path is `""`. Alternatively, we can specify the context path,
as described in xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced `MockMvcWebClientBuilder`].
@@ -73,8 +83,11 @@ as described in xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#
Once we have a reference to the `HtmlPage`, we can then fill out the form and submit it
to create a message, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
HtmlForm form = createMsgFormPage.getHtmlElementById("messageForm");
HtmlTextInput summaryInput = createMsgFormPage.getHtmlElementById("summary");
@@ -84,8 +97,10 @@ to create a message, as the following example shows:
HtmlSubmitInput submit = form.getOneHtmlElementByAttribute("input", "type", "submit");
HtmlPage newMessagePage = submit.click();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val form = createMsgFormPage.getHtmlElementById("messageForm")
val summaryInput = createMsgFormPage.getHtmlElementById("summary")
@@ -95,12 +110,16 @@ to create a message, as the following example shows:
val submit = form.getOneHtmlElementByAttribute("input", "type", "submit")
val newMessagePage = submit.click()
----
======
Finally, we can verify that a new message was created successfully. The following
assertions use the https://assertj.github.io/doc/[AssertJ] library:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
assertThat(newMessagePage.getUrl().toString()).endsWith("/messages/123");
String id = newMessagePage.getHtmlElementById("id").getTextContent();
@@ -110,8 +129,10 @@ assertions use the https://assertj.github.io/doc/[AssertJ] library:
String text = newMessagePage.getHtmlElementById("text").getTextContent();
assertThat(text).isEqualTo("In case you didn't know, Spring Rocks!");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
assertThat(newMessagePage.getUrl().toString()).endsWith("/messages/123")
val id = newMessagePage.getHtmlElementById("id").getTextContent()
@@ -121,6 +142,7 @@ assertions use the https://assertj.github.io/doc/[AssertJ] library:
val text = newMessagePage.getHtmlElementById("text").getTextContent()
assertThat(text).isEqualTo("In case you didn't know, Spring Rocks!")
----
======
The preceding code improves on our
xref:testing/spring-mvc-test-framework/server-htmlunit/why.adoc#spring-mvc-test-server-htmlunit-mock-mvc-test[MockMvc test] in a number of ways.
@@ -142,8 +164,11 @@ In the examples so far, we have used `MockMvcWebClientBuilder` in the simplest w
possible, by building a `WebClient` based on the `WebApplicationContext` loaded for us by
the Spring TestContext Framework. This approach is repeated in the following example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebClient webClient;
@@ -155,8 +180,9 @@ the Spring TestContext Framework. This approach is repeated in the following exa
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
lateinit var webClient: WebClient
@@ -167,11 +193,15 @@ the Spring TestContext Framework. This approach is repeated in the following exa
.build()
}
----
======
We can also specify additional configuration options, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebClient webClient;
@@ -188,8 +218,10 @@ We can also specify additional configuration options, as the following example s
.build();
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
lateinit var webClient: WebClient
@@ -206,12 +238,16 @@ We can also specify additional configuration options, as the following example s
.build()
}
----
======
As an alternative, we can perform the exact same setup by configuring the `MockMvc`
instance separately and supplying it to the `MockMvcWebClientBuilder`, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup(context)
@@ -228,11 +264,13 @@ instance separately and supplying it to the `MockMvcWebClientBuilder`, as follow
.build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed
----
======
This is more verbose, but, by building the `WebClient` with a `MockMvc` instance, we have
the full power of MockMvc at our fingertips.

View File

@@ -26,25 +26,34 @@ afterwards.
If one of the fields were named "`summary`", we might have something that resembles the
following repeated in multiple places within our tests:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
HtmlTextInput summaryInput = currentPage.getHtmlElementById("summary");
summaryInput.setValueAttribute(summary);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val summaryInput = currentPage.getHtmlElementById("summary")
summaryInput.setValueAttribute(summary)
----
======
So what happens if we change the `id` to `smmry`? Doing so would force us to update all
of our tests to incorporate this change. This violates the DRY principle, so we should
ideally extract this code into its own method, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public HtmlPage createMessage(HtmlPage currentPage, String summary, String text) {
setSummary(currentPage, summary);
@@ -57,8 +66,9 @@ ideally extract this code into its own method, as follows:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
fun createMessage(currentPage: HtmlPage, summary:String, text:String) :HtmlPage{
setSummary(currentPage, summary);
@@ -70,14 +80,18 @@ ideally extract this code into its own method, as follows:
summaryInput.setValueAttribute(summary)
}
----
======
Doing so ensures that we do not have to update all of our tests if we change the UI.
We might even take this a step further and place this logic within an `Object` that
represents the `HtmlPage` we are currently on, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class CreateMessagePage {
@@ -111,8 +125,10 @@ represents the `HtmlPage` we are currently on, as the following example shows:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class CreateMessagePage(private val currentPage: HtmlPage) {
@@ -139,6 +155,7 @@ represents the `HtmlPage` we are currently on, as the following example shows:
}
}
----
======
Formerly, this pattern was known as the
https://github.com/SeleniumHQ/selenium/wiki/PageObjects[Page Object Pattern]. While we
@@ -154,8 +171,11 @@ includes a test dependency on `org.seleniumhq.selenium:selenium-htmlunit-driver`
We can easily create a Selenium WebDriver that integrates with MockMvc by using the
`MockMvcHtmlUnitDriverBuilder` as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebDriver driver;
@@ -166,8 +186,10 @@ We can easily create a Selenium WebDriver that integrates with MockMvc by using
.build();
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
lateinit var driver: WebDriver
@@ -178,6 +200,7 @@ We can easily create a Selenium WebDriver that integrates with MockMvc by using
.build()
}
----
======
NOTE: This is a simple example of using `MockMvcHtmlUnitDriverBuilder`. For more advanced
usage, see xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-advanced-builder[Advanced `MockMvcHtmlUnitDriverBuilder`].
@@ -195,35 +218,45 @@ application to a Servlet container. For example, we can request the view to crea
message with the following:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
CreateMessagePage page = CreateMessagePage.to(driver);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val page = CreateMessagePage.to(driver)
----
======
--
We can then fill out the form and submit it to create a message, as follows:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
ViewMessagePage viewMessagePage =
page.createMessage(ViewMessagePage.class, expectedSummary, expectedText);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val viewMessagePage =
page.createMessage(ViewMessagePage::class, expectedSummary, expectedText)
----
======
--
This improves on the design of our xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-usage[HtmlUnit test]
@@ -233,8 +266,11 @@ with HtmlUnit, but it is much easier with WebDriver. Consider the following
`CreateMessagePage` implementation:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class CreateMessagePage extends AbstractPage { // <1>
@@ -262,6 +298,7 @@ with HtmlUnit, but it is much easier with WebDriver. Consider the following
}
}
----
======
<1> `CreateMessagePage` extends the `AbstractPage`. We do not go over the details of
`AbstractPage`, but, in summary, it contains common functionality for all of our pages.
For example, if our application has a navigational bar, global error messages, and other
@@ -327,26 +364,35 @@ Finally, we can verify that a new message was created successfully. The followin
assertions use the https://assertj.github.io/doc/[AssertJ] assertion library:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
assertThat(viewMessagePage.getMessage()).isEqualTo(expectedMessage);
assertThat(viewMessagePage.getSuccess()).isEqualTo("Successfully created a new message");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
assertThat(viewMessagePage.message).isEqualTo(expectedMessage)
assertThat(viewMessagePage.success).isEqualTo("Successfully created a new message")
----
======
--
We can see that our `ViewMessagePage` lets us interact with our custom domain model. For
example, it exposes a method that returns a `Message` object:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public Message getMessage() throws ParseException {
Message message = new Message();
@@ -357,11 +403,14 @@ example, it exposes a method that returns a `Message` object:
return message;
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
fun getMessage() = Message(getId(), getCreated(), getSummary(), getText())
----
======
--
We can then use the rich domain objects in our assertions.
@@ -370,8 +419,11 @@ Lastly, we must not forget to close the `WebDriver` instance when the test is co
as follows:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@AfterEach
void destroy() {
@@ -381,8 +433,9 @@ as follows:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@AfterEach
fun destroy() {
@@ -391,6 +444,7 @@ as follows:
}
}
----
======
--
For additional information on using WebDriver, see the Selenium
@@ -403,8 +457,11 @@ In the examples so far, we have used `MockMvcHtmlUnitDriverBuilder` in the simpl
possible, by building a `WebDriver` based on the `WebApplicationContext` loaded for us by
the Spring TestContext Framework. This approach is repeated here, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebDriver driver;
@@ -416,8 +473,9 @@ the Spring TestContext Framework. This approach is repeated here, as follows:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
lateinit var driver: WebDriver
@@ -428,11 +486,15 @@ the Spring TestContext Framework. This approach is repeated here, as follows:
.build()
}
----
======
We can also specify additional configuration options, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebDriver driver;
@@ -449,8 +511,10 @@ We can also specify additional configuration options, as follows:
.build();
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
lateinit var driver: WebDriver
@@ -467,12 +531,16 @@ We can also specify additional configuration options, as follows:
.build()
}
----
======
As an alternative, we can perform the exact same setup by configuring the `MockMvc`
instance separately and supplying it to the `MockMvcHtmlUnitDriverBuilder`, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup(context)
@@ -489,11 +557,13 @@ instance separately and supplying it to the `MockMvcHtmlUnitDriverBuilder`, as f
.build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed
----
======
This is more verbose, but, by building the `WebDriver` with a `MockMvc` instance, we have
the full power of MockMvc at our fingertips.

View File

@@ -8,8 +8,11 @@ supports paging through all messages. How would you go about testing it?
With Spring MVC Test, we can easily test if we are able to create a `Message`, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
MockHttpServletRequestBuilder createMessage = post("/messages/")
.param("summary", "Spring Rocks")
@@ -19,8 +22,10 @@ With Spring MVC Test, we can easily test if we are able to create a `Message`, a
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/messages/123"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
fun test() {
@@ -33,6 +38,7 @@ With Spring MVC Test, we can easily test if we are able to create a `Message`, a
}
}
----
======
What if we want to test the form view that lets us create the message? For example,
assume our form looks like the following snippet:
@@ -57,31 +63,39 @@ assume our form looks like the following snippet:
How do we ensure that our form produce the correct request to create a new message? A
naive attempt might resemble the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(get("/messages/form"))
.andExpect(xpath("//input[@name='summary']").exists())
.andExpect(xpath("//textarea[@name='text']").exists());
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
mockMvc.get("/messages/form").andExpect {
xpath("//input[@name='summary']") { exists() }
xpath("//textarea[@name='text']") { exists() }
}
----
======
This test has some obvious drawbacks. If we update our controller to use the parameter
`message` instead of `text`, our form test continues to pass, even though the HTML form
is out of synch with the controller. To resolve this we can combine our two tests, as
follows:
[tabs]
======
Java::
+
[[spring-mvc-test-server-htmlunit-mock-mvc-test]]
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
String summaryParamName = "summary";
String textParamName = "text";
@@ -98,8 +112,9 @@ follows:
.andExpect(redirectedUrl("/messages/123"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val summaryParamName = "summary";
val textParamName = "text";
@@ -115,6 +130,7 @@ follows:
redirectedUrl("/messages/123")
}
----
======
This would reduce the risk of our test incorrectly passing, but there are still some
problems:

View File

@@ -7,16 +7,20 @@ xref:testing/webtestclient.adoc#webtestclient-tests[Writing Tests] instead.
To perform requests that use any HTTP method, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// static import of MockMvcRequestBuilders.*
mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.post
@@ -24,19 +28,24 @@ To perform requests that use any HTTP method, as the following example shows:
accept = MediaType.APPLICATION_JSON
}
----
======
You can also perform file upload requests that internally use
`MockMultipartHttpServletRequest` so that there is no actual parsing of a multipart
request. Rather, you have to set it up to be similar to the following example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(multipart("/doc").file("a1", "ABC".getBytes("UTF-8")));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.multipart
@@ -44,30 +53,42 @@ request. Rather, you have to set it up to be similar to the following example:
file("a1", "ABC".toByteArray(charset("UTF8")))
}
----
======
You can specify query parameters in URI template style, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(get("/hotels?thing={thing}", "somewhere"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
mockMvc.get("/hotels?thing={thing}", "somewhere")
----
======
You can also add Servlet request parameters that represent either query or form
parameters, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(get("/hotels").param("thing", "somewhere"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.get
@@ -75,6 +96,7 @@ parameters, as the following example shows:
param("thing", "somewhere")
}
----
======
If application code relies on Servlet request parameters and does not check the query
string explicitly (as is most often the case), it does not matter which option you use.
@@ -87,13 +109,18 @@ request URI. If you must test with the full request URI, be sure to set the `con
and `servletPath` accordingly so that request mappings work, as the following example
shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.get
@@ -102,13 +129,17 @@ shows:
servletPath = "/main"
}
----
======
In the preceding example, it would be cumbersome to set the `contextPath` and
`servletPath` with every performed request. Instead, you can set up default request
properties, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
class MyWebTests {
@@ -123,11 +154,14 @@ properties, as the following example shows:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed
----
======
The preceding properties affect every request performed through the `MockMvc` instance.
If the same property is also specified on a given request, it overrides the default

View File

@@ -7,8 +7,11 @@ point to Spring configuration with Spring MVC and controller infrastructure in i
To set up MockMvc for testing a specific controller, use the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
class MyWebTests {
@@ -24,8 +27,9 @@ To set up MockMvc for testing a specific controller, use the following:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class MyWebTests {
@@ -40,6 +44,7 @@ To set up MockMvc for testing a specific controller, use the following:
}
----
======
Or you can also use this setup when testing through the
xref:testing/webtestclient.adoc#webtestclient-controller-config[WebTestClient] which delegates to the same builder
@@ -47,8 +52,11 @@ as shown above.
To set up MockMvc through Spring configuration, use the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig(locations = "my-servlet-context.xml")
class MyWebTests {
@@ -65,8 +73,9 @@ To set up MockMvc through Spring configuration, use the following:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig(locations = ["my-servlet-context.xml"])
class MyWebTests {
@@ -82,6 +91,7 @@ To set up MockMvc through Spring configuration, use the following:
}
----
======
Or you can also use this setup when testing through the
xref:testing/webtestclient.adoc#webtestclient-context-config[WebTestClient] which delegates to the same builder
@@ -108,8 +118,11 @@ a mock service with Mockito:
You can then inject the mock service into the test to set up and verify your
expectations, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig(locations = "test-servlet-context.xml")
class AccountTests {
@@ -128,8 +141,10 @@ expectations, as the following example shows:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig(locations = ["test-servlet-context.xml"])
class AccountTests {
@@ -148,6 +163,7 @@ expectations, as the following example shows:
}
----
======
The `standaloneSetup`, on the other hand, is a little closer to a unit test. It tests one
controller at a time. You can manually inject the controller with mock dependencies, and

View File

@@ -6,8 +6,11 @@ some common and very useful features. For example, you can declare an `Accept` h
all requests and expect a status of 200 as well as a `Content-Type` header in all
responses, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// static import of MockMvcBuilders.standaloneSetup
@@ -18,19 +21,24 @@ responses, as follows:
.build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed
----
======
In addition, third-party frameworks (and applications) can pre-package setup
instructions, such as those in a `MockMvcConfigurer`. The Spring Framework has one such
built-in implementation that helps to save and re-use the HTTP session across requests.
You can use it as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// static import of SharedHttpSessionConfigurer.sharedHttpSession
@@ -41,11 +49,13 @@ You can use it as follows:
// Use mockMvc to perform requests...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed
----
======
See the javadoc for
{api-spring-framework}/test/web/servlet/setup/ConfigurableMockMvcBuilder.html[`ConfigurableMockMvcBuilder`]

View File

@@ -5,8 +5,11 @@ The best way to test streaming responses such as Server-Sent Events is through t
<<WebTestClient>> which can be used as a test client to connect to a `MockMvc` instance
to perform tests on Spring MVC controllers without a running server. For example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebTestClient client = MockMvcWebTestClient.bindToController(new SseController()).build();
@@ -26,6 +29,7 @@ to perform tests on Spring MVC controllers without a running server. For example
.thenCancel()
.verify();
----
======
`WebTestClient` can also connect to a live server and perform full end-to-end integration
tests. This is also supported in Spring Boot where you can

View File

@@ -28,8 +28,11 @@ https://assertj.github.io/doc/[AssertJ] to assert the types of application event
published while invoking a method in a Spring-managed component:
// Don't use "quotes" in the "subs" section because of the asterisks in /* ... */
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim",role="primary"]
.Java
----
@SpringJUnitConfig(/* ... */)
@RecordApplicationEvents // <1>
@@ -51,6 +54,7 @@ published while invoking a method in a Spring-managed component:
}
}
----
======
<1> Annotate the test class with `@RecordApplicationEvents`.
<2> Inject the `ApplicationEvents` instance for the current test.
<3> Use the `ApplicationEvents` API to count how many `OrderSubmitted` events were published.

View File

@@ -16,8 +16,11 @@ As an alternative to implementing the `ApplicationContextAware` interface, you c
the application context for your test class through the `@Autowired` annotation on either
a field or setter method, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig
class MyTest {
@@ -28,6 +31,7 @@ a field or setter method, as the following example shows:
// class body...
}
----
======
<1> Injecting the `ApplicationContext`.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -48,8 +52,11 @@ a field or setter method, as the following example shows:
Similarly, if your test is configured to load a `WebApplicationContext`, you can inject
the web application context into your test, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig // <1>
class MyWebAppTest {
@@ -60,6 +67,7 @@ the web application context into your test, as follows:
// class body...
}
----
======
<1> Configuring the `WebApplicationContext`.
<2> Injecting the `WebApplicationContext`.

View File

@@ -38,8 +38,11 @@ ensure that each subclass gets its own `ApplicationContext` with the correct dyn
properties.
====
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(/* ... */)
@Testcontainers
@@ -59,8 +62,10 @@ properties.
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(/* ... */)
@Testcontainers
@@ -85,6 +90,7 @@ properties.
}
----
======
[[precedence]]
== Precedence

View File

@@ -59,8 +59,11 @@ Consider two examples with XML configuration and `@Configuration` classes:
</beans>
----
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "classpath:/app-config.xml"
@@ -77,8 +80,10 @@ Consider two examples with XML configuration and `@Configuration` classes:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from "classpath:/app-config.xml"
@@ -95,6 +100,7 @@ Consider two examples with XML configuration and `@Configuration` classes:
}
}
----
======
When `TransferServiceTest` is run, its `ApplicationContext` is loaded from the
`app-config.xml` configuration file in the root of the classpath. If you inspect
@@ -118,8 +124,11 @@ but define an in-memory data source as a default when neither of these is active
The following code listings demonstrate how to implement the same configuration and
integration test with `@Configuration` classes instead of XML:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Configuration
@Profile("dev")
@@ -135,8 +144,10 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
@Profile("dev")
@@ -152,9 +163,13 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Configuration
@Profile("production")
@@ -167,8 +182,10 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
@Profile("production")
@@ -181,9 +198,13 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Configuration
@Profile("default")
@@ -198,8 +219,10 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
@Profile("default")
@@ -214,9 +237,13 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Configuration
public class TransferServiceConfig {
@@ -239,8 +266,10 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
class TransferServiceConfig {
@@ -264,9 +293,13 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig({
TransferServiceConfig.class,
@@ -285,8 +318,10 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(
TransferServiceConfig::class,
@@ -305,6 +340,7 @@ integration test with `@Configuration` classes instead of XML:
}
}
----
======
In this variation, we have split the XML configuration into four independent
`@Configuration` classes:
@@ -333,8 +369,11 @@ has been moved to an abstract superclass, `AbstractIntegrationTest`:
NOTE: As of Spring Framework 5.3, test configuration may also be inherited from enclosing
classes. See xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit-jupiter-nested-test-configuration[`@Nested` test class configuration] for details.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig({
TransferServiceConfig.class,
@@ -346,8 +385,9 @@ classes. See xref:testing/testcontext-framework/support-classes.adoc#testcontext
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(
TransferServiceConfig::class,
@@ -358,9 +398,13 @@ classes. See xref:testing/testcontext-framework/support-classes.adoc#testcontext
abstract class AbstractIntegrationTest {
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// "dev" profile inherited from superclass
class TransferServiceTest extends AbstractIntegrationTest {
@@ -374,8 +418,10 @@ classes. See xref:testing/testcontext-framework/support-classes.adoc#testcontext
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// "dev" profile inherited from superclass
class TransferServiceTest : AbstractIntegrationTest() {
@@ -389,12 +435,16 @@ classes. See xref:testing/testcontext-framework/support-classes.adoc#testcontext
}
}
----
======
`@ActiveProfiles` also supports an `inheritProfiles` attribute that can be used to
disable the inheritance of active profiles, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// "dev" profile overridden with "production"
@ActiveProfiles(profiles = "production", inheritProfiles = false)
@@ -403,8 +453,9 @@ disable the inheritance of active profiles, as the following example shows:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// "dev" profile overridden with "production"
@ActiveProfiles("production", inheritProfiles = false)
@@ -412,6 +463,7 @@ disable the inheritance of active profiles, as the following example shows:
// test body
}
----
======
[[testcontext-ctx-management-env-profiles-ActiveProfilesResolver]]
Furthermore, it is sometimes necessary to resolve active profiles for tests
@@ -430,8 +482,11 @@ attribute of `@ActiveProfiles`. For further information, see the corresponding
The following example demonstrates how to implement and register a custom
`OperatingSystemActiveProfilesResolver`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// "dev" profile overridden programmatically via a custom resolver
@ActiveProfiles(
@@ -442,8 +497,9 @@ The following example demonstrates how to implement and register a custom
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// "dev" profile overridden programmatically via a custom resolver
@ActiveProfiles(
@@ -453,9 +509,13 @@ The following example demonstrates how to implement and register a custom
// test body
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class OperatingSystemActiveProfilesResolver implements ActiveProfilesResolver {
@@ -467,8 +527,10 @@ The following example demonstrates how to implement and register a custom
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class OperatingSystemActiveProfilesResolver : ActiveProfilesResolver {
@@ -479,4 +541,5 @@ The following example demonstrates how to implement and register a custom
}
}
----
======

View File

@@ -14,8 +14,11 @@ TestContext Framework is enabled automatically if Groovy is on the classpath.
The following example shows how to specify Groovy configuration files:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "/AppConfig.groovy" and
@@ -25,6 +28,7 @@ The following example shows how to specify Groovy configuration files:
// class body...
}
----
======
<1> Specifying the location of Groovy configuration files.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -49,8 +53,11 @@ detect a default location based on the name of the test class. If your class is
`"classpath:com/example/MyTestContext.groovy"`. The following example shows how to use
the default:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
@@ -60,6 +67,7 @@ the default:
// class body...
}
----
======
<1> Loading configuration from the default location.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -87,8 +95,11 @@ configured resource location ends with `.xml`, it is loaded by using an
The following listing shows how to combine both in an integration test:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
@@ -98,8 +109,10 @@ The following listing shows how to combine both in an integration test:
// class body...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from
@@ -109,5 +122,6 @@ The following listing shows how to combine both in an integration test:
// class body...
}
----
======
=====

View File

@@ -35,8 +35,11 @@ one for the root `WebApplicationContext` (loaded by using the `TestAppConfig`
that is autowired into the test instance is the one for the child context (that is, the
lowest context in the hierarchy). The following listing shows this configuration scenario:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@@ -53,8 +56,9 @@ lowest context in the hierarchy). The following listing shows this configuration
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@WebAppConfiguration
@@ -69,6 +73,7 @@ lowest context in the hierarchy). The following listing shows this configuration
// ...
}
----
======
--
**Class hierarchy with implicit parent context**
@@ -86,8 +91,11 @@ based on the configuration in `AbstractWebTests` is set as the parent context fo
the contexts loaded for the concrete subclasses. The following listing shows this
configuration scenario:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@@ -100,8 +108,10 @@ configuration scenario:
@ContextHierarchy(@ContextConfiguration("/spring/rest-ws-config.xml"))
public class RestWebServiceTests extends AbstractWebTests {}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@WebAppConfiguration
@@ -115,6 +125,7 @@ configuration scenario:
class RestWebServiceTests : AbstractWebTests()
----
======
--
**Class hierarchy with merged context hierarchy configuration**
@@ -131,8 +142,11 @@ application context loaded from `/app-config.xml` is set as the parent context f
contexts loaded from `/user-config.xml` and `{"/user-config.xml", "/order-config.xml"}`.
The following listing shows this configuration scenario:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@@ -147,8 +161,9 @@ The following listing shows this configuration scenario:
class ExtendedTests extends BaseTests {}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
@@ -161,6 +176,7 @@ The following listing shows this configuration scenario:
)
class ExtendedTests : BaseTests() {}
----
======
--
**Class hierarchy with overridden context hierarchy configuration**
@@ -172,8 +188,11 @@ application context for `ExtendedTests` is loaded only from `/test-user-config.x
has its parent set to the context loaded from `/app-config.xml`. The following listing
shows this configuration scenario:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@@ -190,8 +209,10 @@ shows this configuration scenario:
))
class ExtendedTests extends BaseTests {}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
@@ -207,6 +228,7 @@ shows this configuration scenario:
))
class ExtendedTests : BaseTests() {}
----
======
.Dirtying a context within a context hierarchy
NOTE: If you use `@DirtiesContext` in a test whose context is configured as part of a

View File

@@ -26,8 +26,11 @@ Beans defined in `extended-config.xml` can, therefore, override (that is, replac
defined in `base-config.xml`. The following example shows how one class can extend
another and use both its own configuration file and the superclass's configuration file:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "/base-config.xml"
@@ -44,6 +47,7 @@ another and use both its own configuration file and the superclass's configurati
// class body...
}
----
======
<1> Configuration file defined in the superclass.
<2> Configuration file defined in the subclass.
@@ -75,8 +79,11 @@ order. Beans defined in `ExtendedConfig` can, therefore, override (that is, repl
those defined in `BaseConfig`. The following example shows how one class can extend
another and use both its own configuration class and the superclass's configuration class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// ApplicationContext will be loaded from BaseConfig
@SpringJUnitConfig(BaseConfig.class) // <1>
@@ -90,6 +97,7 @@ another and use both its own configuration class and the superclass's configurat
// class body...
}
----
======
<1> Configuration class defined in the superclass.
<2> Configuration class defined in the subclass.
@@ -119,8 +127,11 @@ implement Spring's `Ordered` interface or are annotated with Spring's `@Order` a
or the standard `@Priority` annotation. The following example shows how one class can
extend another and use both its own initializer and the superclass's initializer:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// ApplicationContext will be initialized by BaseInitializer
@SpringJUnitConfig(initializers = BaseInitializer.class) // <1>
@@ -135,6 +146,7 @@ extend another and use both its own initializer and the superclass's initializer
// class body...
}
----
======
<1> Initializer defined in the superclass.
<2> Initializer defined in the subclass.

View File

@@ -13,8 +13,11 @@ order in which the initializers are invoked depends on whether they implement Sp
`Ordered` interface or are annotated with Spring's `@Order` annotation or the standard
`@Priority` annotation. The following example shows how to use initializers:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from TestConfig
@@ -26,6 +29,7 @@ order in which the initializers are invoked depends on whether they implement Sp
// class body...
}
----
======
<1> Specifying configuration by using a configuration class and an initializer.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -50,8 +54,11 @@ component classes in `@ContextConfiguration` entirely and instead declare only
in the context -- for example, by programmatically loading bean definitions from XML
files or configuration classes. The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be initialized by EntireAppInitializer
@@ -61,6 +68,7 @@ files or configuration classes. The following example shows how to do so:
// class body...
}
----
======
<1> Specifying configuration by using only an initializer.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -6,8 +6,11 @@ xref:core/beans/java.adoc[Java-based container configuration]), you can annotate
class with `@ContextConfiguration` and configure the `classes` attribute with an array
that contains references to component classes. The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from AppConfig and TestConfig
@@ -16,6 +19,7 @@ that contains references to component classes. The following example shows how t
// class body...
}
----
======
<1> Specifying component classes.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -64,8 +68,11 @@ example, the `OrderServiceTest` class declares a `static` nested configuration c
named `Config` that is automatically used to load the `ApplicationContext` for the test
class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig <1>
// ApplicationContext will be loaded from the static nested Config class
@@ -93,6 +100,7 @@ class:
}
----
======
<1> Loading configuration information from the nested `Config` class.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -40,8 +40,11 @@ loaded by using the specified resource protocol. Resource location wildcards (su
The following example uses a test properties file:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestPropertySource("/test.properties") // <1>
@@ -49,6 +52,7 @@ The following example uses a test properties file:
// class body...
}
----
======
<1> Specifying a properties file with an absolute path.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -77,8 +81,11 @@ a Java properties file:
The following example sets two inlined properties:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port: 4242"}) // <1>
@@ -86,6 +93,7 @@ The following example sets two inlined properties:
// class body...
}
----
======
<1> Setting two properties by using two variations of the key-value syntax.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -147,8 +155,11 @@ entries for the `timezone` and `port` properties those are overridden by the inl
properties declared by using the `properties` attribute. The following example shows how
to specify properties both in a file and inline:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestPropertySource(
@@ -160,8 +171,9 @@ to specify properties both in a file and inline:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestPropertySource("/test.properties",
@@ -171,6 +183,7 @@ to specify properties both in a file and inline:
// class body...
}
----
======
[[inheriting-and-overriding-test-property-sources]]
== Inheriting and Overriding Test Property Sources
@@ -199,8 +212,11 @@ for `ExtendedTest` is loaded by using the `base.properties` and `extended.proper
files as test property source locations. The following example shows how to define
properties in both a subclass and its superclass by using `properties` files:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@TestPropertySource("base.properties")
@ContextConfiguration
@@ -214,8 +230,10 @@ properties in both a subclass and its superclass by using `properties` files:
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@TestPropertySource("base.properties")
@ContextConfiguration
@@ -229,14 +247,18 @@ properties in both a subclass and its superclass by using `properties` files:
// ...
}
----
======
In the next example, the `ApplicationContext` for `BaseTest` is loaded by using only the
inlined `key1` property. In contrast, the `ApplicationContext` for `ExtendedTest` is
loaded by using the inlined `key1` and `key2` properties. The following example shows how
to define properties in both a subclass and its superclass by using inline properties:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@TestPropertySource(properties = "key1 = value1")
@ContextConfiguration
@@ -250,8 +272,10 @@ to define properties in both a subclass and its superclass by using inline prope
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@TestPropertySource(properties = ["key1 = value1"])
@ContextConfiguration
@@ -265,4 +289,5 @@ to define properties in both a subclass and its superclass by using inline prope
// ...
}
----
======

View File

@@ -18,9 +18,11 @@ mocks can be autowired into your test instance. Note that the `WebApplicationCon
`MockServletContext` are both cached across the test suite, whereas the other mocks are
managed per test method by the `ServletTestExecutionListener`.
.Injecting mocks
[tabs]
======
Injecting mocks::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig
class WacTests {
@@ -47,8 +49,9 @@ managed per test method by the `ServletTestExecutionListener`.
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig
class WacTests {
@@ -74,4 +77,5 @@ managed per test method by the `ServletTestExecutionListener`.
//...
}
----
======

View File

@@ -29,9 +29,11 @@ The remaining examples in this section show some of the various configuration op
loading a `WebApplicationContext`. The following example shows the TestContext
framework's support for convention over configuration:
.Conventions
[tabs]
======
Conventions::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@@ -45,8 +47,10 @@ framework's support for convention over configuration:
//...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@@ -60,6 +64,7 @@ framework's support for convention over configuration:
//...
}
----
======
If you annotate a test class with `@WebAppConfiguration` without specifying a resource
base path, the resource path effectively defaults to `file:src/main/webapp`. Similarly,
@@ -71,9 +76,11 @@ as the `WacTests` class or static nested `@Configuration` classes).
The following example shows how to explicitly declare a resource base path with
`@WebAppConfiguration` and an XML resource location with `@ContextConfiguration`:
.Default resource semantics
[tabs]
======
Default resource semantics::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@@ -86,8 +93,10 @@ The following example shows how to explicitly declare a resource base path with
//...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@@ -100,6 +109,7 @@ The following example shows how to explicitly declare a resource base path with
//...
}
----
======
The important thing to note here is the different semantics for paths with these two
annotations. By default, `@WebAppConfiguration` resource paths are file system based,
@@ -108,9 +118,11 @@ whereas `@ContextConfiguration` resource locations are classpath based.
The following example shows that we can override the default resource semantics for both
annotations by specifying a Spring resource prefix:
.Explicit resource semantics
[tabs]
======
Explicit resource semantics::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@@ -123,8 +135,10 @@ annotations by specifying a Spring resource prefix:
//...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
@@ -137,6 +151,7 @@ annotations by specifying a Spring resource prefix:
//...
}
----
======
Contrast the comments in this example with the previous example.

View File

@@ -10,8 +10,11 @@ is treated as an absolute classpath location (for example, `/org/example/config.
path that represents a resource URL (i.e., a path prefixed with `classpath:`, `file:`,
`http:`, etc.) is used _as is_.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from "/app-config.xml" and
@@ -21,6 +24,7 @@ path that represents a resource URL (i.e., a path prefixed with `classpath:`, `f
// class body...
}
----
======
<1> Setting the locations attribute to a list of XML files.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -43,8 +47,11 @@ attributes in `@ContextConfiguration`, you can omit the declaration of the `loca
attribute name and declare the resource locations by using the shorthand format
demonstrated in the following example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@ContextConfiguration({"/app-config.xml", "/test-config.xml"}) <1>
@@ -52,6 +59,7 @@ demonstrated in the following example:
// class body...
}
----
======
<1> Specifying XML files without using the `locations` attribute.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -74,8 +82,11 @@ class. If your class is named `com.example.MyTest`, `GenericXmlContextLoader` lo
application context from `"classpath:com/example/MyTest-context.xml"`. The following
example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// ApplicationContext will be loaded from
@@ -85,6 +96,7 @@ example shows how to do so:
// class body...
}
----
======
<1> Loading configuration from the default location.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -46,8 +46,11 @@ to run the populator against a `javax.sql.DataSource`. The following example
specifies SQL scripts for a test schema and test data, sets the statement separator to
`@@`, and run the scripts against a `DataSource`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
void databaseTest() {
@@ -60,8 +63,10 @@ specifies SQL scripts for a test schema and test data, sets the statement separa
// run code that uses the test schema and data
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
fun databaseTest() {
@@ -74,6 +79,7 @@ specifies SQL scripts for a test schema and test data, sets the statement separa
// run code that uses the test schema and data
}
----
======
Note that `ResourceDatabasePopulator` internally delegates to `ScriptUtils` for parsing
and running SQL scripts. Similarly, the `executeSqlScript(..)` methods in
@@ -110,8 +116,11 @@ the specified resource protocol.
The following example shows how to use `@Sql` at the class level and at the method level
within a JUnit Jupiter based integration test class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig
@Sql("/test-schema.sql")
@@ -130,8 +139,9 @@ within a JUnit Jupiter based integration test class:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig
@Sql("/test-schema.sql")
@@ -149,6 +159,7 @@ within a JUnit Jupiter based integration test class:
}
}
----
======
[[testcontext-executing-sql-declaratively-script-detection]]
=== Default Script Detection
@@ -175,8 +186,11 @@ Java 8, you can use `@Sql` as a repeatable annotation. Otherwise, you can use th
The following example shows how to use `@Sql` as a repeatable annotation with Java 8:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@Sql(scripts = "/test-schema.sql", config = @SqlConfig(commentPrefix = "`"))
@@ -185,11 +199,14 @@ The following example shows how to use `@Sql` as a repeatable annotation with Ja
// run code that uses the test schema and test data
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Repeatable annotations with non-SOURCE retention are not yet supported by Kotlin
----
======
In the scenario presented in the preceding example, the `test-schema.sql` script uses a
different syntax for single-line comments.
@@ -199,8 +216,11 @@ declarations are grouped together within `@SqlGroup`. With Java 8 and above, the
`@SqlGroup` is optional, but you may need to use `@SqlGroup` for compatibility with
other JVM languages such as Kotlin.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@SqlGroup({
@@ -211,8 +231,10 @@ other JVM languages such as Kotlin.
// run code that uses the test schema and test data
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
@SqlGroup(
@@ -222,6 +244,7 @@ other JVM languages such as Kotlin.
// Run code that uses the test schema and test data
}
----
======
[[testcontext-executing-sql-declaratively-script-execution-phases]]
=== Script Execution Phases
@@ -231,8 +254,11 @@ you need to run a particular set of scripts after the test method (for example,
up database state), you can use the `executionPhase` attribute in `@Sql`, as the
following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Test
@Sql(
@@ -249,8 +275,10 @@ following example shows:
// to the database outside of the test's transaction
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
@SqlGroup(
@@ -264,6 +292,7 @@ following example shows:
// to the database outside of the test's transaction
}
----
======
Note that `ISOLATED` and `AFTER_TEST_METHOD` are statically imported from
`Sql.TransactionMode` and `Sql.ExecutionPhase`, respectively.
@@ -319,8 +348,11 @@ reference manual, the javadoc for
provide detailed information, and the following example shows a typical testing scenario
that uses JUnit Jupiter and transactional tests with `@Sql`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestDatabaseConfig.class)
@Transactional
@@ -351,8 +383,10 @@ that uses JUnit Jupiter and transactional tests with `@Sql`:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestDatabaseConfig::class)
@Transactional
@@ -378,6 +412,7 @@ that uses JUnit Jupiter and transactional tests with `@Sql`:
}
}
----
======
Note that there is no need to clean up the database after the `usersTest()` method is
run, since any changes made to the database (either within the test method or within the

View File

@@ -54,8 +54,11 @@ example.
The first code listing shows a JUnit Jupiter based implementation of the test class that
uses `@Autowired` for field injection:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@@ -74,8 +77,9 @@ uses `@Autowired` for field injection:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
// specifies the Spring configuration to load for this test fixture
@@ -93,12 +97,16 @@ uses `@Autowired` for field injection:
}
}
----
======
Alternatively, you can configure the class to use `@Autowired` for setter injection, as
follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@@ -121,8 +129,9 @@ follows:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension::class)
// specifies the Spring configuration to load for this test fixture
@@ -144,6 +153,7 @@ follows:
}
}
----
======
The preceding code listings use the same XML context file referenced by the
`@ContextConfiguration` annotation (that is, `repository-config.xml`). The following
@@ -178,8 +188,11 @@ such a case, you can override the setter method and use the `@Qualifier` annotat
indicate a specific target bean, as follows (but make sure to delegate to the overridden
method in the superclass as well):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// ...
@@ -192,8 +205,9 @@ method in the superclass as well):
// ...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// ...
@@ -204,6 +218,7 @@ method in the superclass as well):
// ...
----
======
The specified qualifier value indicates the specific `DataSource` bean to inject,
narrowing the set of type matches to a specific bean. Its value is matched against

View File

@@ -20,8 +20,11 @@ xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit4-rules
The following code listing shows the minimal requirements for configuring a test class to
run with the custom Spring `Runner`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RunWith(SpringRunner.class)
@TestExecutionListeners({})
@@ -34,8 +37,9 @@ run with the custom Spring `Runner`:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RunWith(SpringRunner::class)
@TestExecutionListeners
@@ -47,6 +51,7 @@ run with the custom Spring `Runner`:
}
}
----
======
In the preceding example, `@TestExecutionListeners` is configured with an empty list, to
disable the default listeners, which otherwise would require an `ApplicationContext` to
@@ -74,8 +79,11 @@ To support the full functionality of the TestContext framework, you must combine
`SpringClassRule` with a `SpringMethodRule`. The following example shows the proper way
to declare these rules in an integration test:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// Optionally specify a non-Spring Runner via @RunWith(...)
@ContextConfiguration
@@ -94,8 +102,9 @@ to declare these rules in an integration test:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Optionally specify a non-Spring Runner via @RunWith(...)
@ContextConfiguration
@@ -115,6 +124,7 @@ to declare these rules in an integration test:
}
}
----
======
[[testcontext-support-classes-junit4]]
== JUnit 4 Support Classes
@@ -179,8 +189,11 @@ TestNG:
The following code listing shows how to configure a test class to use the
`SpringExtension` in conjunction with `@ContextConfiguration`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// Instructs JUnit Jupiter to extend the test with Spring support.
@ExtendWith(SpringExtension.class)
@@ -195,8 +208,9 @@ The following code listing shows how to configure a test class to use the
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Instructs JUnit Jupiter to extend the test with Spring support.
@ExtendWith(SpringExtension::class)
@@ -210,6 +224,7 @@ The following code listing shows how to configure a test class to use the
}
}
----
======
Since you can also use annotations in JUnit 5 as meta-annotations, Spring provides the
`@SpringJUnitConfig` and `@SpringJUnitWebConfig` composed annotations to simplify the
@@ -218,8 +233,11 @@ configuration of the test `ApplicationContext` and JUnit Jupiter.
The following example uses `@SpringJUnitConfig` to reduce the amount of configuration
used in the previous example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load an ApplicationContext from TestConfig.class
@@ -233,8 +251,9 @@ used in the previous example:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load an ApplicationContext from TestConfig.class
@@ -247,12 +266,16 @@ used in the previous example:
}
}
----
======
Similarly, the following example uses `@SpringJUnitWebConfig` to create a
`WebApplicationContext` for use with JUnit Jupiter:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load a WebApplicationContext from TestWebConfig.class
@@ -266,8 +289,9 @@ Similarly, the following example uses `@SpringJUnitWebConfig` to create a
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load a WebApplicationContext from TestWebConfig::class
@@ -280,6 +304,7 @@ Similarly, the following example uses `@SpringJUnitWebConfig` to create a
}
}
----
======
See the documentation for `@SpringJUnitConfig` and `@SpringJUnitWebConfig` in
xref:testing/annotations/integration-junit-jupiter.adoc[Spring JUnit Jupiter Testing Annotations] for further details.
@@ -345,8 +370,11 @@ In the following example, Spring injects the `OrderService` bean from the
`ApplicationContext` loaded from `TestConfig.class` into the
`OrderServiceIntegrationTests` constructor.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {
@@ -362,8 +390,9 @@ In the following example, Spring injects the `OrderService` bean from the
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests @Autowired constructor(private val orderService: OrderService){
@@ -371,6 +400,7 @@ In the following example, Spring injects the `OrderService` bean from the
}
----
======
Note that this feature lets test dependencies be `final` and therefore immutable.
@@ -378,8 +408,11 @@ If the `spring.test.constructor.autowire.mode` property is to `all` (see
xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-testconstructor[`@TestConstructor`]), we can omit the declaration of
`@Autowired` on the constructor in the previous example, resulting in the following.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {
@@ -394,14 +427,16 @@ xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-anno
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests(val orderService:OrderService) {
// tests that use the injected OrderService
}
----
======
[[testcontext-junit-jupiter-di-method]]
==== Method Injection
@@ -414,8 +449,11 @@ parameter with the corresponding bean from the test's `ApplicationContext`.
In the following example, Spring injects the `OrderService` from the `ApplicationContext`
loaded from `TestConfig.class` into the `deleteOrder()` test method:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {
@@ -427,8 +465,9 @@ loaded from `TestConfig.class` into the `deleteOrder()` test method:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests {
@@ -439,6 +478,7 @@ loaded from `TestConfig.class` into the `deleteOrder()` test method:
}
}
----
======
Due to the robustness of the `ParameterResolver` support in JUnit Jupiter, you can also
have multiple dependencies injected into a single method, not only from Spring but also
@@ -447,8 +487,11 @@ from JUnit Jupiter itself or other third-party extensions.
The following example shows how to have both Spring and JUnit Jupiter inject dependencies
into the `placeOrderRepeatedly()` test method simultaneously.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {
@@ -463,8 +506,9 @@ into the `placeOrderRepeatedly()` test method simultaneously.
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests {
@@ -477,6 +521,7 @@ into the `placeOrderRepeatedly()` test method simultaneously.
}
}
----
======
Note that the use of `@RepeatedTest` from JUnit Jupiter lets the test method gain access
to the `RepetitionInfo`.
@@ -514,8 +559,11 @@ xref:testing/testcontext-framework/ctx-management/caching.adoc[Context Caching]
xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-nestedtestconfiguration[supported annotations] to see
which annotations can be inherited in `@Nested` test classes.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
class GreetingServiceTests {
@@ -542,8 +590,9 @@ which annotations can be inherited in `@Nested` test classes.
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
class GreetingServiceTests {
@@ -569,6 +618,7 @@ which annotations can be inherited in `@Nested` test classes.
}
}
----
======
[[testcontext-support-classes-testng]]
== TestNG Support Classes

View File

@@ -37,8 +37,11 @@ If you extend a class that is annotated with `@TestExecutionListeners` and you n
switch to using the default set of listeners, you can annotate your class with the
following.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// Switch to default listeners
@TestExecutionListeners(
@@ -50,8 +53,9 @@ following.
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Switch to default listeners
@TestExecutionListeners(
@@ -62,6 +66,7 @@ following.
// class body...
}
----
======
====
[[testcontext-tel-config-automatic-discovery]]
@@ -103,8 +108,11 @@ default listeners are not registered. In most common testing scenarios, this eff
forces the developer to manually declare all default listeners in addition to any custom
listeners. The following listing demonstrates this style of configuration:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestExecutionListeners({
@@ -121,8 +129,9 @@ listeners. The following listing demonstrates this style of configuration:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestExecutionListeners(
@@ -138,6 +147,7 @@ listeners. The following listing demonstrates this style of configuration:
// class body...
}
----
======
The challenge with this approach is that it requires that the developer know exactly
which listeners are registered by default. Moreover, the set of default listeners can
@@ -165,8 +175,11 @@ configures its `order` value (for example, `500`) to be less than the order of t
defaults in front of the `ServletTestExecutionListener`, and the previous example could
be replaced with the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration
@TestExecutionListeners(
@@ -177,8 +190,10 @@ be replaced with the following:
// class body...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestExecutionListeners(
@@ -189,4 +204,5 @@ be replaced with the following:
// class body...
}
----
======

View File

@@ -102,8 +102,11 @@ are preconfigured for transactional support at the class level.
The following example demonstrates a common scenario for writing an integration test for
a Hibernate-based `UserRepository`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(TestConfig.class)
@Transactional
@@ -145,8 +148,9 @@ a Hibernate-based `UserRepository`:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
@Transactional
@@ -187,6 +191,7 @@ a Hibernate-based `UserRepository`:
}
}
----
======
As explained in xref:testing/testcontext-framework/tx.adoc#testcontext-tx-rollback-and-commit-behavior[Transaction Rollback and Commit Behavior], there is no need to
clean up the database after the `createUser()` method runs, since any changes made to the
@@ -214,8 +219,11 @@ The following example demonstrates some of the features of `TestTransaction`. Se
javadoc for {api-spring-framework}/test/context/transaction/TestTransaction.html[`TestTransaction`]
for further details.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ContextConfiguration(classes = TestConfig.class)
public class ProgrammaticTransactionManagementTests extends
@@ -244,8 +252,10 @@ for further details.
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration(classes = [TestConfig::class])
class ProgrammaticTransactionManagementTests : AbstractTransactionalJUnit4SpringContextTests() {
@@ -273,6 +283,7 @@ for further details.
}
}
----
======
[[testcontext-tx-before-and-after-tx]]
== Running Code Outside of a Transaction
@@ -318,8 +329,11 @@ information and configuration examples. xref:testing/testcontext-framework/execu
declarative SQL script execution with default transaction rollback semantics. The
following example shows the relevant annotations:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig
@Transactional(transactionManager = "txMgr")
@@ -356,8 +370,9 @@ following example shows the relevant annotations:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig
@Transactional(transactionManager = "txMgr")
@@ -393,6 +408,7 @@ following example shows the relevant annotations:
}
----
======
[[testcontext-tx-false-positives]]
.Avoid false positives when testing ORM code
@@ -407,8 +423,11 @@ of work. In the following Hibernate-based example test case, one method demonstr
false positive, and the other method correctly exposes the results of flushing the
session:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// ...
@@ -434,8 +453,9 @@ session:
// ...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// ...
@@ -460,11 +480,15 @@ session:
// ...
----
======
The following example shows matching methods for JPA:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// ...
@@ -489,8 +513,10 @@ The following example shows matching methods for JPA:
// ...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// ...
@@ -515,6 +541,7 @@ The following example shows matching methods for JPA:
// ...
----
======
=====
[[testcontext-tx-orm-lifecycle-callbacks]]
@@ -539,8 +566,11 @@ The following example shows how to flush the `EntityManager` to ensure that
a `@PostPersist` callback method has been registered for the `Person` entity used in the
example.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// ...
@@ -565,8 +595,10 @@ example.
// ...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// ...
@@ -591,6 +623,7 @@ example.
// ...
----
======
See
https://github.com/spring-projects/spring-framework/blob/main/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/orm/JpaEntityListenerTests.java[JpaEntityListenerTests]

View File

@@ -47,9 +47,11 @@ the provided `MockHttpServletRequest`. When the `loginUser()` method is invoked
set parameters). We can then perform assertions against the results based on the known
inputs for the username and password. The following listing shows how to do so:
.Request-scoped bean test
[tabs]
======
Request-scoped bean test::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig
class RequestScopedBeanTests {
@@ -67,8 +69,10 @@ inputs for the username and password. The following listing shows how to do so:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig
class RequestScopedBeanTests {
@@ -86,6 +90,7 @@ inputs for the username and password. The following listing shows how to do so:
}
}
----
======
The following code snippet is similar to the one we saw earlier for a request-scoped
bean. However, this time, the `userService` bean has a dependency on a session-scoped
@@ -119,9 +124,11 @@ the user service has access to the session-scoped `userPreferences` for the curr
`MockHttpSession`, and we can perform assertions against the results based on the
configured theme. The following example shows how to do so:
.Session-scoped bean test
[tabs]
======
Session-scoped bean test::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig
class SessionScopedBeanTests {
@@ -139,8 +146,9 @@ configured theme. The following example shows how to do so:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig
class SessionScopedBeanTests {
@@ -157,4 +165,5 @@ configured theme. The following example shows how to do so:
}
}
----
======

View File

@@ -32,17 +32,23 @@ xref:web/webflux/dispatcher-handler.adoc#webflux-framework-config[WebFlux Java c
controller(s), and creates a xref:web/webflux/reactive-spring.adoc#webflux-web-handler-api[WebHandler chain]
to handle requests:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebTestClient client =
WebTestClient.bindToController(new TestController()).build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val client = WebTestClient.bindToController(TestController()).build()
----
======
For Spring MVC, use the following which delegates to the
{api-spring-framework}/test/web/servlet/setup/StandaloneMockMvcBuilder.html[StandaloneMockMvcBuilder]
@@ -50,17 +56,23 @@ to load infrastructure equivalent to the xref:web/webmvc/mvc-config.adoc[WebMvc
registers the given controller(s), and creates an instance of
xref:testing/spring-mvc-test-framework.adoc[MockMvc] to handle requests:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
WebTestClient client =
MockMvcWebTestClient.bindToController(new TestController()).build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val client = MockMvcWebTestClient.bindToController(TestController()).build()
----
======
@@ -76,8 +88,11 @@ For WebFlux, use the following where the Spring `ApplicationContext` is passed t
to create the xref:web/webflux/reactive-spring.adoc#webflux-web-handler-api[WebHandler chain] to handle
requests:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitConfig(WebConfig.class) // <1>
class MyTests {
@@ -90,6 +105,7 @@ requests:
}
}
----
======
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
@@ -117,8 +133,11 @@ For Spring MVC, use the following where the Spring `ApplicationContext` is passe
to create a xref:testing/spring-mvc-test-framework.adoc[MockMvc] instance to handle
requests:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@WebAppConfiguration("classpath:META-INF/web-resources") // <1>
@@ -139,6 +158,7 @@ requests:
}
}
----
======
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
@@ -180,18 +200,24 @@ mock request and response objects, without a running server.
For WebFlux, use the following which delegates to `RouterFunctions.toWebHandler` to
create a server setup to handle requests:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
RouterFunction<?> route = ...
client = WebTestClient.bindToRouterFunction(route).build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val route: RouterFunction<*> = ...
val client = WebTestClient.bindToRouterFunction(route).build()
----
======
For Spring MVC there are currently no options to test
xref:web/webmvc-functional.adoc[WebMvc functional endpoints].
@@ -203,16 +229,22 @@ xref:web/webmvc-functional.adoc[WebMvc functional endpoints].
This setup connects to a running server to perform full, end-to-end HTTP tests:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build()
----
======
@@ -225,22 +257,28 @@ are readily available following `bindToServer()`. For all other configuration op
you need to use `configureClient()` to transition from server to client configuration, as
follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client = WebTestClient.bindToController(new TestController())
.configureClient()
.baseUrl("/test")
.build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client = WebTestClient.bindToController(TestController())
.configureClient()
.baseUrl("/test")
.build()
----
======
@@ -258,8 +296,11 @@ instead continues with a workflow to verify responses.
To assert the response status and headers, use the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client.get().uri("/persons/1")
.accept(MediaType.APPLICATION_JSON)
@@ -267,8 +308,10 @@ To assert the response status and headers, use the following:
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client.get().uri("/persons/1")
.accept(MediaType.APPLICATION_JSON)
@@ -276,14 +319,18 @@ To assert the response status and headers, use the following:
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON)
----
======
If you would like for all expectations to be asserted even if one of them fails, you can
use `expectAll(..)` instead of multiple chained `expect*(..)` calls. This feature is
similar to the _soft assertions_ support in AssertJ and the `assertAll()` support in
JUnit Jupiter.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client.get().uri("/persons/1")
.accept(MediaType.APPLICATION_JSON)
@@ -293,6 +340,7 @@ JUnit Jupiter.
spec -> spec.expectHeader().contentType(MediaType.APPLICATION_JSON)
);
----
======
You can then choose to decode the response body through one of the following:
@@ -302,16 +350,21 @@ You can then choose to decode the response body through one of the following:
And perform assertions on the resulting higher level Object(s):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client.get().uri("/persons")
.exchange()
.expectStatus().isOk()
.expectBodyList(Person.class).hasSize(3).contains(person);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.reactive.server.expectBodyList
@@ -320,12 +373,16 @@ And perform assertions on the resulting higher level Object(s):
.expectStatus().isOk()
.expectBodyList<Person>().hasSize(3).contains(person)
----
======
If the built-in assertions are insufficient, you can consume the object instead and
perform any other assertions:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import org.springframework.test.web.reactive.server.expectBody
@@ -337,8 +394,10 @@ perform any other assertions:
// custom assertions (e.g. AssertJ)...
});
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client.get().uri("/persons/1")
.exchange()
@@ -348,11 +407,15 @@ perform any other assertions:
// custom assertions (e.g. AssertJ)...
}
----
======
Or you can exit the workflow and obtain an `EntityExchangeResult`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
EntityExchangeResult<Person> result = client.get().uri("/persons/1")
.exchange()
@@ -360,8 +423,10 @@ Or you can exit the workflow and obtain an `EntityExchangeResult`:
.expectBody(Person.class)
.returnResult();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.reactive.server.expectBody
@@ -371,6 +436,7 @@ Or you can exit the workflow and obtain an `EntityExchangeResult`:
.expectBody<Person>()
.returnResult()
----
======
TIP: When you need to decode to a target type with generics, look for the overloaded methods
that accept
@@ -384,8 +450,11 @@ instead of `Class<T>`.
If the response is not expected to have content, you can assert that as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client.post().uri("/persons")
.body(personMono, Person.class)
@@ -393,8 +462,10 @@ If the response is not expected to have content, you can assert that as follows:
.expectStatus().isCreated()
.expectBody().isEmpty();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client.post().uri("/persons")
.bodyValue(person)
@@ -402,26 +473,33 @@ If the response is not expected to have content, you can assert that as follows:
.expectStatus().isCreated()
.expectBody().isEmpty()
----
======
If you want to ignore the response content, the following releases the content without
any assertions:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client.get().uri("/persons/123")
.exchange()
.expectStatus().isNotFound()
.expectBody(Void.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client.get().uri("/persons/123")
.exchange()
.expectStatus().isNotFound
.expectBody<Unit>()
----
======
@@ -433,8 +511,11 @@ content rather than through higher level Object(s).
To verify the full JSON content with https://jsonassert.skyscreamer.org[JSONAssert]:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client.get().uri("/persons/1")
.exchange()
@@ -442,8 +523,10 @@ To verify the full JSON content with https://jsonassert.skyscreamer.org[JSONAsse
.expectBody()
.json("{\"name\":\"Jane\"}")
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client.get().uri("/persons/1")
.exchange()
@@ -451,11 +534,15 @@ To verify the full JSON content with https://jsonassert.skyscreamer.org[JSONAsse
.expectBody()
.json("{\"name\":\"Jane\"}")
----
======
To verify JSON content with https://github.com/jayway/JsonPath[JSONPath]:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client.get().uri("/persons")
.exchange()
@@ -464,8 +551,10 @@ To verify JSON content with https://github.com/jayway/JsonPath[JSONPath]:
.jsonPath("$[0].name").isEqualTo("Jane")
.jsonPath("$[1].name").isEqualTo("Jason");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client.get().uri("/persons")
.exchange()
@@ -474,6 +563,7 @@ To verify JSON content with https://github.com/jayway/JsonPath[JSONPath]:
.jsonPath("$[0].name").isEqualTo("Jane")
.jsonPath("$[1].name").isEqualTo("Jason")
----
======
@@ -484,8 +574,11 @@ To test potentially infinite streams such as `"text/event-stream"` or
`"application/x-ndjson"`, start by verifying the response status and headers, and then
obtain a `FluxExchangeResult`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
FluxExchangeResult<MyEvent> result = client.get().uri("/events")
.accept(TEXT_EVENT_STREAM)
@@ -494,8 +587,10 @@ obtain a `FluxExchangeResult`:
.returnResult(MyEvent.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.reactive.server.returnResult
@@ -505,11 +600,15 @@ obtain a `FluxExchangeResult`:
.expectStatus().isOk()
.returnResult<MyEvent>()
----
======
Now you're ready to consume the response stream with `StepVerifier` from `reactor-test`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
Flux<Event> eventFlux = result.getResponseBody();
@@ -520,8 +619,10 @@ Now you're ready to consume the response stream with `StepVerifier` from `reacto
.thenCancel()
.verify();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val eventFlux = result.getResponseBody()
@@ -532,6 +633,7 @@ Now you're ready to consume the response stream with `StepVerifier` from `reacto
.thenCancel()
.verify()
----
======
[[webtestclient-mockmvc]]
@@ -544,8 +646,11 @@ When testing a Spring MVC application with a MockMvc server setup, you have the
choice to perform further assertions on the server response. To do that start by
obtaining an `ExchangeResult` after asserting the body:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// For a response with a body
EntityExchangeResult<Person> result = client.get().uri("/persons/1")
@@ -559,8 +664,10 @@ obtaining an `ExchangeResult` after asserting the body:
.exchange()
.expectBody().isEmpty();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// For a response with a body
val result = client.get().uri("/persons/1")
@@ -574,21 +681,28 @@ obtaining an `ExchangeResult` after asserting the body:
.exchange()
.expectBody().isEmpty();
----
======
Then switch to MockMvc server response assertions:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
MockMvcWebTestClient.resultActionsFor(result)
.andExpect(model().attribute("integer", 3))
.andExpect(model().attribute("string", "a string value"));
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
MockMvcWebTestClient.resultActionsFor(result)
.andExpect(model().attribute("integer", 3))
.andExpect(model().attribute("string", "a string value"));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
MockMvcWebTestClient.resultActionsFor(result)
.andExpect(model().attribute("integer", 3))
.andExpect(model().attribute("string", "a string value"));
----
======