Migrate to Asciidoctor Tabs
This commit is contained in:
@@ -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]
|
||||
====
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
@@ -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...
|
||||
}
|
||||
----
|
||||
======
|
||||
=====
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
// ...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
@@ -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`.
|
||||
//...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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:
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
@@ -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"));
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
Reference in New Issue
Block a user