-
Notifications
You must be signed in to change notification settings - Fork 38.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reorganize and modularize the Testing chapter in the reference manual
Closes gh-29522
- Loading branch information
Showing
10 changed files
with
9,047 additions
and
9,051 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
155 changes: 155 additions & 0 deletions
155
framework-docs/src/docs/asciidoc/testing/integration-testing.adoc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
[[integration-testing]] | ||
= Integration Testing | ||
|
||
It is important to be able to perform some integration testing without requiring | ||
deployment to your application server or connecting to other enterprise infrastructure. | ||
Doing so lets you test things such as: | ||
|
||
* The correct wiring of your Spring IoC container contexts. | ||
* Data access using JDBC or an ORM tool. This can include such things as the correctness | ||
of SQL statements, Hibernate queries, JPA entity mappings, and so forth. | ||
|
||
The Spring Framework provides first-class support for integration testing in the | ||
`spring-test` module. The name of the actual JAR file might include the release version | ||
and might also be in the long `org.springframework.test` form, depending on where you get | ||
it from (see the <<core.adoc#beans-dependencies, section on Dependency Management>> | ||
for an explanation). This library includes the `org.springframework.test` package, which | ||
contains valuable classes for integration testing with a Spring container. This testing | ||
does not rely on an application server or other deployment environment. Such tests are | ||
slower to run than unit tests but much faster than the equivalent Selenium tests or | ||
remote tests that rely on deployment to an application server. | ||
|
||
Unit and integration testing support is provided in the form of the annotation-driven | ||
<<testcontext-framework, Spring TestContext Framework>>. The TestContext framework is | ||
agnostic of the actual testing framework in use, which allows instrumentation of tests | ||
in various environments, including JUnit, TestNG, and others. | ||
|
||
The following section provides an overview of the high-level goals of Spring's | ||
integration support, and the rest of this chapter then focuses on dedicated topics: | ||
|
||
* <<integration-testing-support-jdbc>> | ||
* <<testcontext-framework>> | ||
* <<webtestclient>> | ||
* <<spring-mvc-test-framework>> | ||
* <<spring-mvc-test-client>> | ||
* <<integration-testing-annotations>> | ||
|
||
|
||
|
||
[[integration-testing-goals]] | ||
== Goals of Integration Testing | ||
|
||
Spring's integration testing support has the following primary goals: | ||
|
||
* To manage <<testing-ctx-management, Spring IoC container caching>> between tests. | ||
* To provide <<testing-fixture-di, Dependency Injection of test fixture instances>>. | ||
* To provide <<testing-tx, transaction management>> appropriate to integration testing. | ||
* To supply <<testing-support-classes, Spring-specific base classes>> that assist | ||
developers in writing integration tests. | ||
|
||
The next few sections describe each goal and provide links to implementation and | ||
configuration details. | ||
|
||
|
||
[[testing-ctx-management]] | ||
=== Context Management and Caching | ||
|
||
The Spring TestContext Framework provides consistent loading of Spring | ||
`ApplicationContext` instances and `WebApplicationContext` instances as well as caching | ||
of those contexts. Support for the caching of loaded contexts is important, because | ||
startup time can become an issue -- not because of the overhead of Spring itself, but | ||
because the objects instantiated by the Spring container take time to instantiate. For | ||
example, a project with 50 to 100 Hibernate mapping files might take 10 to 20 seconds to | ||
load the mapping files, and incurring that cost before running every test in every test | ||
fixture leads to slower overall test runs that reduce developer productivity. | ||
|
||
Test classes typically declare either an array of resource locations for XML or Groovy | ||
configuration metadata -- often in the classpath -- or an array of component classes that | ||
is used to configure the application. These locations or classes are the same as or | ||
similar to those specified in `web.xml` or other configuration files for production | ||
deployments. | ||
|
||
By default, once loaded, the configured `ApplicationContext` is reused for each test. | ||
Thus, the setup cost is incurred only once per test suite, and subsequent test execution | ||
is much faster. In this context, the term "`test suite`" means all tests run in the same | ||
JVM -- for example, all tests run from an Ant, Maven, or Gradle build for a given project | ||
or module. In the unlikely case that a test corrupts the application context and requires | ||
reloading (for example, by modifying a bean definition or the state of an application | ||
object) the TestContext framework can be configured to reload the configuration and | ||
rebuild the application context before executing the next test. | ||
|
||
See <<testcontext-ctx-management>> and <<testcontext-ctx-management-caching>> with the | ||
TestContext framework. | ||
|
||
|
||
[[testing-fixture-di]] | ||
=== Dependency Injection of Test Fixtures | ||
|
||
When the TestContext framework loads your application context, it can optionally | ||
configure instances of your test classes by using Dependency Injection. This provides a | ||
convenient mechanism for setting up test fixtures by using preconfigured beans from your | ||
application context. A strong benefit here is that you can reuse application contexts | ||
across various testing scenarios (for example, for configuring Spring-managed object | ||
graphs, transactional proxies, `DataSource` instances, and others), thus avoiding the | ||
need to duplicate complex test fixture setup for individual test cases. | ||
|
||
As an example, consider a scenario where we have a class (`HibernateTitleRepository`) | ||
that implements data access logic for a `Title` domain entity. We want to write | ||
integration tests that test the following areas: | ||
|
||
* The Spring configuration: Basically, is everything related to the configuration of the | ||
`HibernateTitleRepository` bean correct and present? | ||
* The Hibernate mapping file configuration: Is everything mapped correctly and are the | ||
correct lazy-loading settings in place? | ||
* The logic of the `HibernateTitleRepository`: Does the configured instance of this class | ||
perform as anticipated? | ||
|
||
See dependency injection of test fixtures with the | ||
<<testcontext-fixture-di, TestContext framework>>. | ||
|
||
|
||
[[testing-tx]] | ||
=== Transaction Management | ||
|
||
One common issue in tests that access a real database is their effect on the state of the | ||
persistence store. Even when you use a development database, changes to the state may | ||
affect future tests. Also, many operations -- such as inserting or modifying persistent | ||
data -- cannot be performed (or verified) outside of a transaction. | ||
|
||
The TestContext framework addresses this issue. By default, the framework creates and | ||
rolls back a transaction for each test. You can write code that can assume the existence | ||
of a transaction. If you call transactionally proxied objects in your tests, they behave | ||
correctly, according to their configured transactional semantics. In addition, if a test | ||
method deletes the contents of selected tables while running within the transaction | ||
managed for the test, the transaction rolls back by default, and the database returns to | ||
its state prior to execution of the test. Transactional support is provided to a test by | ||
using a `PlatformTransactionManager` bean defined in the test's application context. | ||
|
||
If you want a transaction to commit (unusual, but occasionally useful when you want a | ||
particular test to populate or modify the database), you can tell the TestContext | ||
framework to cause the transaction to commit instead of roll back by using the | ||
<<integration-testing-annotations, `@Commit`>> annotation. | ||
|
||
See transaction management with the <<testcontext-tx, TestContext framework>>. | ||
|
||
|
||
[[testing-support-classes]] | ||
=== Support Classes for Integration Testing | ||
|
||
The Spring TestContext Framework provides several `abstract` support classes that | ||
simplify the writing of integration tests. These base test classes provide well-defined | ||
hooks into the testing framework as well as convenient instance variables and methods, | ||
which let you access: | ||
|
||
* The `ApplicationContext`, for performing explicit bean lookups or testing the state of | ||
the context as a whole. | ||
* A `JdbcTemplate`, for executing SQL statements to query the database. You can use such | ||
queries to confirm database state both before and after execution of database-related | ||
application code, and Spring ensures that such queries run in the scope of the same | ||
transaction as the application code. When used in conjunction with an ORM tool, be sure | ||
to avoid <<testcontext-tx-false-positives, false positives>>. | ||
|
||
In addition, you may want to create your own custom, application-wide superclass with | ||
instance variables and methods specific to your project. | ||
|
||
See support classes for the <<testcontext-support-classes, TestContext framework>>. |
136 changes: 136 additions & 0 deletions
136
framework-docs/src/docs/asciidoc/testing/spring-mvc-test-client.adoc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
[[spring-mvc-test-client]] | ||
= Testing Client Applications | ||
|
||
You can use client-side tests to test code that internally uses the `RestTemplate`. The | ||
idea is to declare expected requests and to provide "`stub`" responses so that you can | ||
focus on testing the code in isolation (that is, without running a server). The following | ||
example shows how to do so: | ||
|
||
[source,java,indent=0,subs="verbatim,quotes",role="primary"] | ||
.Java | ||
---- | ||
RestTemplate restTemplate = new RestTemplate(); | ||
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build(); | ||
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess()); | ||
// Test code that uses the above RestTemplate ... | ||
mockServer.verify(); | ||
---- | ||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||
.Kotlin | ||
---- | ||
val restTemplate = RestTemplate() | ||
val mockServer = MockRestServiceServer.bindTo(restTemplate).build() | ||
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess()) | ||
// Test code that uses the above RestTemplate ... | ||
mockServer.verify() | ||
---- | ||
|
||
In the preceding example, `MockRestServiceServer` (the central class for client-side REST | ||
tests) configures the `RestTemplate` with a custom `ClientHttpRequestFactory` that | ||
asserts actual requests against expectations and returns "`stub`" responses. In this | ||
case, we expect a request to `/greeting` and want to return a 200 response with | ||
`text/plain` content. We can define additional expected requests and stub responses as | ||
needed. When we define expected requests and stub responses, the `RestTemplate` can be | ||
used in client-side code as usual. At the end of testing, `mockServer.verify()` can be | ||
used to verify that all expectations have been satisfied. | ||
|
||
By default, requests are expected in the order in which expectations were declared. You | ||
can set the `ignoreExpectOrder` option when building the server, in which case all | ||
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`: | ||
|
||
[source,java,indent=0,subs="verbatim,quotes",role="primary"] | ||
.Java | ||
---- | ||
server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build(); | ||
---- | ||
[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`: | ||
|
||
[source,java,indent=0,subs="verbatim,quotes",role="primary"] | ||
.Java | ||
---- | ||
RestTemplate restTemplate = new RestTemplate(); | ||
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build(); | ||
mockServer.expect(times(2), requestTo("/something")).andRespond(withSuccess()); | ||
mockServer.expect(times(3), requestTo("/somewhere")).andRespond(withSuccess()); | ||
// ... | ||
mockServer.verify(); | ||
---- | ||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||
.Kotlin | ||
---- | ||
val restTemplate = RestTemplate() | ||
val mockServer = MockRestServiceServer.bindTo(restTemplate).build() | ||
mockServer.expect(times(2), requestTo("/something")).andRespond(withSuccess()) | ||
mockServer.expect(times(3), requestTo("/somewhere")).andRespond(withSuccess()) | ||
// ... | ||
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 | ||
expected request. For example if "/something" is expected two times followed by | ||
"/somewhere" three times, then there should be a request to "/something" before there is | ||
a request to "/somewhere", but, aside from that subsequent "/something" and "/somewhere", | ||
requests can come at any time. | ||
|
||
As an alternative to all of the above, the client-side test support also provides a | ||
`ClientHttpRequestFactory` implementation that you can configure into a `RestTemplate` to | ||
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: | ||
|
||
[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 ... | ||
---- | ||
[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 ... | ||
---- | ||
|
||
[[spring-mvc-test-client-static-imports]] | ||
== Static Imports | ||
|
||
As with server-side tests, the fluent API for client-side tests requires a few static | ||
imports. Those are easy to find by searching for `MockRest*`. Eclipse users should add | ||
`MockRestRequestMatchers.{asterisk}` and `MockRestResponseCreators.{asterisk}` as | ||
"`favorite static members`" in the Eclipse preferences under Java -> Editor -> Content | ||
Assist -> Favorites. That allows using content assist after typing the first character of | ||
the static method name. Other IDEs (such IntelliJ) may not require any additional | ||
configuration. Check for the support for code completion on static members. | ||
|
||
[[spring-mvc-test-client-resources]] | ||
== Further Examples of Client-side REST Tests | ||
|
||
Spring MVC Test's own tests include | ||
{spring-framework-main-code}/spring-test/src/test/java/org/springframework/test/web/client/samples[example | ||
tests] of client-side REST tests. |
Oops, something went wrong.