diff --git a/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java b/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java index 726bb791794..bfc7032e85e 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java @@ -26,8 +26,6 @@ import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpResponse; import org.springframework.mock.http.client.MockAsyncClientHttpRequest; -import org.springframework.test.web.client.match.MockRestRequestMatchers; -import org.springframework.test.web.client.response.MockRestResponseCreators; import org.springframework.util.Assert; import org.springframework.web.client.AsyncRestTemplate; import org.springframework.web.client.RestTemplate; @@ -46,7 +44,7 @@ import org.springframework.web.client.support.RestGatewaySupport; * *
  * RestTemplate restTemplate = new RestTemplate()
- * MockRestServiceServer server = MockRestServiceServer.restTemplate(restTemplate).build();
+ * MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
  *
  * server.expect(manyTimes(), requestTo("/hotels/42")).andExpect(method(HttpMethod.GET))
  *     .andRespond(withSuccess("{ \"id\" : \"42\", \"name\" : \"Holiday Inn\"}", MediaType.APPLICATION_JSON));
@@ -125,56 +123,59 @@ public class MockRestServiceServer {
 
 
 	/**
-	 * Build a {@code MockRestServiceServer} for a {@code RestTemplate}.
+	 * Return a builder for a {@code MockRestServiceServer} that should be used
+	 * to reply to the given {@code RestTemplate}.
 	 * @since 4.3
 	 */
-	public static MockRestServiceServerBuilder restTemplate(RestTemplate restTemplate) {
+	public static MockRestServiceServerBuilder bindTo(RestTemplate restTemplate) {
 		return new DefaultBuilder(restTemplate);
 	}
 
 	/**
-	 * Build a {@code MockRestServiceServer} for an {@code AsyncRestTemplate}.
+	 * Return a builder for a {@code MockRestServiceServer} that should be used
+	 * to reply to the given {@code AsyncRestTemplate}.
 	 * @since 4.3
 	 */
-	public static MockRestServiceServerBuilder asyncRestTemplate(AsyncRestTemplate asyncRestTemplate) {
+	public static MockRestServiceServerBuilder bindTo(AsyncRestTemplate asyncRestTemplate) {
 		return new DefaultBuilder(asyncRestTemplate);
 	}
 
 	/**
-	 * Build a {@code MockRestServiceServer} for a {@code RestGateway}.
+	 * Return a builder for a {@code MockRestServiceServer} that should be used
+	 * to reply to the given {@code RestGatewaySupport}.
 	 * @since 4.3
 	 */
-	public static MockRestServiceServerBuilder restGateway(RestGatewaySupport restGateway) {
+	public static MockRestServiceServerBuilder bindTo(RestGatewaySupport restGateway) {
 		Assert.notNull(restGateway, "'gatewaySupport' must not be null");
 		return new DefaultBuilder(restGateway.getRestTemplate());
 	}
 
 
 	/**
-	 * A shortcut for {@code restTemplate(restTemplate).build()}.
+	 * A shortcut for {@code bindTo(restTemplate).build()}.
 	 * @param restTemplate the RestTemplate to set up for mock testing
 	 * @return the mock server
 	 */
 	public static MockRestServiceServer createServer(RestTemplate restTemplate) {
-		return restTemplate(restTemplate).build();
+		return bindTo(restTemplate).build();
 	}
 
 	/**
-	 * A shortcut for {@code asyncRestTemplate(asyncRestTemplate).build()}.
+	 * A shortcut for {@code bindTo(asyncRestTemplate).build()}.
 	 * @param asyncRestTemplate the AsyncRestTemplate to set up for mock testing
 	 * @return the created mock server
 	 */
 	public static MockRestServiceServer createServer(AsyncRestTemplate asyncRestTemplate) {
-		return asyncRestTemplate(asyncRestTemplate).build();
+		return bindTo(asyncRestTemplate).build();
 	}
 
 	/**
-	 * A shortcut for {@code restGateway(restGateway).build()}.
+	 * A shortcut for {@code bindTo(restGateway).build()}.
 	 * @param restGateway the REST gateway to set up for mock testing
 	 * @return the created mock server
 	 */
 	public static MockRestServiceServer createServer(RestGatewaySupport restGateway) {
-		return restGateway(restGateway).build();
+		return bindTo(restGateway).build();
 	}
 
 
@@ -189,13 +190,13 @@ public class MockRestServiceServer {
 		 * matching the order of declaration. This is a shortcut for:
* {@code builder.expectationManager(new UnorderedRequestExpectationManager)} */ - MockRestServiceServerBuilder unordered(); + MockRestServiceServerBuilder ignoreExpectOrder(); /** * Configure a custom {@code RequestExpectationManager}. *

By default {@link SimpleRequestExpectationManager} is used. It is * also possible to switch to {@link UnorderedRequestExpectationManager} - * by setting {@link #unordered()}. + * by setting {@link #ignoreExpectOrder()}. */ MockRestServiceServerBuilder expectationManager(RequestExpectationManager manager); @@ -231,7 +232,7 @@ public class MockRestServiceServer { @Override - public MockRestServiceServerBuilder unordered() { + public MockRestServiceServerBuilder ignoreExpectOrder() { expectationManager(new UnorderedRequestExpectationManager()); return this; } diff --git a/spring-test/src/test/java/org/springframework/test/web/client/samples/SampleTests.java b/spring-test/src/test/java/org/springframework/test/web/client/samples/SampleTests.java index cb882f7c1b2..2bb264a8047 100644 --- a/spring-test/src/test/java/org/springframework/test/web/client/samples/SampleTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/client/samples/SampleTests.java @@ -23,7 +23,6 @@ import org.springframework.core.io.Resource; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.test.web.Person; -import org.springframework.test.web.client.ExpectedCount; import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.web.client.RestTemplate; @@ -50,7 +49,7 @@ public class SampleTests { @Before public void setup() { this.restTemplate = new RestTemplate(); - this.mockServer = MockRestServiceServer.createServer(this.restTemplate); + this.mockServer = MockRestServiceServer.bindTo(this.restTemplate).ignoreExpectOrder().build(); } @Test diff --git a/src/asciidoc/testing.adoc b/src/asciidoc/testing.adoc index d789e3491b5..d6007bb6e91 100644 --- a/src/asciidoc/testing.adoc +++ b/src/asciidoc/testing.adoc @@ -5045,28 +5045,63 @@ Here is an example: ---- RestTemplate restTemplate = new RestTemplate(); - MockRestServiceServer mockServer = MockRestServiceServer.restTemplate(restTemplate).build(); - mockServer.expect(manyTimes(), requestTo("/greeting")) - .andRespond(withSuccess("Hello world", MediaType.TEXT_PLAIN)); + MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build(); + mockServer.expect(requestTo("/greeting")).andRespond(withSuccess()); // Test code that uses the above RestTemplate ... mockServer.verify(); ---- -In the above example, `MockRestServiceServer` -- the central class for client-side REST -tests -- configures the `RestTemplate` with a custom `ClientHttpRequestFactory` that +In the above 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 single request to "/greeting" and want to return a 200 response with -"text/plain" content. We could define as many additional requests and stub responses as -necessary. Once expected requests and stub responses have been defined, the `RestTemplate` can be -used in client-side code as usual. At the end of the tests `mockServer.verify()` can be -used to verify that all expected requests were performed. +we expect a request to "/greeting" and want to return a 200 response with +"text/plain" content. We could define as additional expected requests and stub responses as +needed. When expected requests and stub responses are defined, 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. -The client-side test support also provides an alternative `ClientHttpRequestFactory` -strategy for executing requests with a `MockMvc` instance. That allows you to -process requests using your server-side code but without running a server. -Here is an example: +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. Here is an example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder().build(); +---- + +Even with unordered requests by default each request is allowed to execute once only. +The `expect` method provides an overloaded variant that accepts an `ExpectedCount` +argument that specifies a count range, e.g. `once`, `manyTimes`, `max`, `min`, +`between`, and so on. Here is an example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + RestTemplate restTemplate = new RestTemplate(); + + MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build(); + mockServer.expect(times(2), requestTo("/foo")).andRespond(withSuccess()); + mockServer.expect(times(3), requestTo("/bar")).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 only applies to the first of +any expected request. For example if "/foo" is expected 2 times followed by "/bar" +3 times, then there should be a request to "/foo" before there is a request to "/bar" +but aside from that subsequent "/foo" and "/bar" 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 can be configured into a `RestTemplate` +to bind it to a `MockMvc` instance. That allows processing requests using actual +server-side logic but without running a server. Here is an example: [source,java,indent=0] [subs="verbatim,quotes"] @@ -5086,7 +5121,7 @@ Here is an example: Just like with server-side tests, the fluent API for client-side tests requires a few static imports. Those are easy to find by searching __"MockRest*"__. Eclipse users should add `"MockRestRequestMatchers.{asterisk}"` and `"MockRestResponseCreators.{asterisk}"` -as "favorite static members" in the Eclipse preferences under +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 (e.g. IntelliJ) may not require any additional diff --git a/src/asciidoc/whats-new.adoc b/src/asciidoc/whats-new.adoc index 006c40722dd..79069b5b955 100644 --- a/src/asciidoc/whats-new.adoc +++ b/src/asciidoc/whats-new.adoc @@ -678,5 +678,6 @@ Spring 4.3 also improves the caching abstraction as follows: * The JUnit support in the _Spring TestContext Framework_ now requires JUnit 4.12 or higher. * Server-side Spring MVC Test supports expectations on response headers with multiple values. * Server-side Spring MVC Test parses form data request content and populates request parameters. -* Client-side Spring MVC Test supports expected count of request executions (once, manyTimes, min, max, etc.) -* Client-side Spring MVC Test supports expectations for form data in the request body. +* Client-side REST test support allows indicating how many times a request is expected and +whether the oder of declaration for expectations should be ignored (see <>) +* Client-side REST Test supports expectations for form data in the request body.