Add ExpectedCount

MockRestServicesServer now supports an expect variant that accepts
a range of expected count of executions.

Issue: SPR-11365
This commit is contained in:
Rossen Stoyanchev
2016-02-23 18:12:32 -05:00
parent 08a08725be
commit 91872b0d74
16 changed files with 808 additions and 206 deletions

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.client;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.mock.http.client.MockAsyncClientHttpRequest;
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.test.web.client.ExpectedCount.once;
import static org.springframework.test.web.client.ExpectedCount.times;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
/**
* Unit tests for {@link DefaultRequestExpectation}.
* @author Rossen Stoyanchev
*/
public class DefaultRequestExpectationTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void match() throws Exception {
RequestExpectation expectation = new DefaultRequestExpectation(once(), requestTo("/foo"));
expectation.match(createRequest(GET, "/foo"));
}
@Test
public void matchWithFailedExpection() throws Exception {
RequestExpectation expectation = new DefaultRequestExpectation(once(), requestTo("/foo"));
expectation.andExpect(method(POST));
this.thrown.expectMessage("Unexpected HttpMethod expected:<POST> but was:<GET>");
expectation.match(createRequest(GET, "/foo"));
}
@Test
public void hasRemainingCount() throws Exception {
RequestExpectation expectation = new DefaultRequestExpectation(times(2), requestTo("/foo"));
expectation.andRespond(withSuccess());
expectation.createResponse(createRequest(GET, "/foo"));
assertTrue(expectation.hasRemainingCount());
expectation.createResponse(createRequest(GET, "/foo"));
assertFalse(expectation.hasRemainingCount());
}
@Test
public void isSatisfied() throws Exception {
RequestExpectation expectation = new DefaultRequestExpectation(times(2), requestTo("/foo"));
expectation.andRespond(withSuccess());
expectation.createResponse(createRequest(GET, "/foo"));
assertFalse(expectation.isSatisfied());
expectation.createResponse(createRequest(GET, "/foo"));
assertTrue(expectation.isSatisfied());
}
private ClientHttpRequest createRequest(HttpMethod method, String url) {
try {
return new MockAsyncClientHttpRequest(method, new URI(url));
}
catch (URISyntaxException ex) {
throw new IllegalStateException(ex);
}
}
}

View File

@@ -19,67 +19,149 @@ package org.springframework.test.web.client;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.mock.http.client.MockAsyncClientHttpRequest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.test.web.client.ExpectedCount.max;
import static org.springframework.test.web.client.ExpectedCount.min;
import static org.springframework.test.web.client.ExpectedCount.once;
import static org.springframework.test.web.client.ExpectedCount.times;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
/**
* Unit tests for {@link AbstractRequestExpectationManager}.
* Unit tests for {@link SimpleRequestExpectationManager}.
* @author Rossen Stoyanchev
*/
public class SimpleRequestExpectationManagerTests {
private SimpleRequestExpectationManager manager = new SimpleRequestExpectationManager();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void validateWithUnexpectedRequest() throws Exception {
public void unexpectedRequest() throws Exception {
try {
this.manager.validateRequest(request(HttpMethod.GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/foo"));
}
catch (AssertionError error) {
assertEquals("No further requests expected: HTTP GET /foo\n" +
"0 out of 0 were executed", error.getMessage());
"0 request(s) executed.\n", error.getMessage());
}
}
@Test
public void verify() throws Exception {
this.manager.expectRequest(anything()).andRespond(withSuccess());
this.manager.expectRequest(anything()).andRespond(withSuccess());
this.manager.validateRequest(request(HttpMethod.GET, "/foo"));
this.manager.validateRequest(request(HttpMethod.POST, "/bar"));
public void zeroExpectedRequests() throws Exception {
this.manager.verify();
}
@Test
public void verifyWithZeroExpectations() throws Exception {
public void sequentialRequests() throws Exception {
this.manager.expectRequest(once(), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(once(), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.verify();
}
@Test
public void verifyWithRemainingExpectations() throws Exception {
this.manager.expectRequest(anything()).andRespond(withSuccess());
this.manager.expectRequest(anything()).andRespond(withSuccess());
public void sequentialRequestsTooMany() throws Exception {
this.manager.expectRequest(max(1), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(max(1), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.validateRequest(request(HttpMethod.GET, "/foo"));
try {
this.manager.verify();
}
catch (AssertionError error) {
assertTrue(error.getMessage(), error.getMessage().contains("1 out of 2 were executed"));
}
this.thrown.expectMessage("No further requests expected: HTTP GET /baz\n" +
"2 request(s) executed:\n" +
"GET /foo\n" +
"GET /bar\n");
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/baz"));
}
private ClientHttpRequest request(HttpMethod method, String url) {
@Test
public void sequentialRequestsTooFew() throws Exception {
this.manager.expectRequest(min(1), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(min(1), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.thrown.expectMessage("Further request(s) expected leaving 1 unsatisfied expectation(s).\n" +
"1 request(s) executed:\nGET /foo\n");
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.verify();
}
@Test
public void repeatedRequests() throws Exception {
this.manager.expectRequest(times(2), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(times(2), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.verify();
}
@Test
public void repeatedRequestsTooMany() throws Exception {
this.manager.expectRequest(max(2), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(max(2), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.thrown.expectMessage("No further requests expected: HTTP GET /foo\n" +
"4 request(s) executed:\n" +
"GET /foo\n" +
"GET /bar\n" +
"GET /foo\n" +
"GET /bar\n");
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
}
@Test
public void repeatedRequestsTooFew() throws Exception {
this.manager.expectRequest(min(2), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(min(2), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.thrown.expectMessage("3 request(s) executed:\n" +
"GET /foo\n" +
"GET /bar\n" +
"GET /foo\n");
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.verify();
}
@Test
public void repeatedRequestsNotInOrder() throws Exception {
this.manager.expectRequest(times(2), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(times(2), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(times(2), requestTo("/baz")).andExpect(method(GET)).andRespond(withSuccess());
this.thrown.expectMessage("Unexpected HttpMethod expected:<GET> but was:<POST>");
this.manager.validateRequest(createRequest(POST, "/foo"));
}
private ClientHttpRequest createRequest(HttpMethod method, String url) {
try {
return new MockAsyncClientHttpRequest(method, new URI(url));
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.client;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.mock.http.client.MockAsyncClientHttpRequest;
import static org.junit.Assert.assertEquals;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.test.web.client.ExpectedCount.max;
import static org.springframework.test.web.client.ExpectedCount.min;
import static org.springframework.test.web.client.ExpectedCount.once;
import static org.springframework.test.web.client.ExpectedCount.times;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
/**
* Unit tests for {@link UnorderedRequestExpectationManager}.
* @author Rossen Stoyanchev
*/
public class UnorderedRequestExpectationManagerTests {
private UnorderedRequestExpectationManager manager = new UnorderedRequestExpectationManager();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void unexpectedRequest() throws Exception {
try {
this.manager.validateRequest(createRequest(GET, "/foo"));
}
catch (AssertionError error) {
assertEquals("No further requests expected: HTTP GET /foo\n" +
"0 request(s) executed.\n", error.getMessage());
}
}
@Test
public void zeroExpectedRequests() throws Exception {
this.manager.verify();
}
@Test
public void multipleRequests() throws Exception {
this.manager.expectRequest(once(), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(once(), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.verify();
}
@Test
public void repeatedRequests() throws Exception {
this.manager.expectRequest(times(2), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(times(2), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.verify();
}
@Test
public void repeatedRequestsTooMany() throws Exception {
this.manager.expectRequest(max(2), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(max(2), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.thrown.expectMessage("No further requests expected: HTTP GET /foo\n" +
"4 request(s) executed:\n" +
"GET /bar\n" +
"GET /foo\n" +
"GET /bar\n" +
"GET /foo\n");
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/foo"));
}
@Test
public void repeatedRequestsTooFew() throws Exception {
this.manager.expectRequest(min(2), requestTo("/foo")).andExpect(method(GET)).andRespond(withSuccess());
this.manager.expectRequest(min(2), requestTo("/bar")).andExpect(method(GET)).andRespond(withSuccess());
this.thrown.expectMessage("3 request(s) executed:\n" +
"GET /bar\n" +
"GET /foo\n" +
"GET /foo\n");
this.manager.validateRequest(createRequest(GET, "/bar"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.validateRequest(createRequest(GET, "/foo"));
this.manager.verify();
}
private ClientHttpRequest createRequest(HttpMethod method, String url) {
try {
return new MockAsyncClientHttpRequest(method, new URI(url));
}
catch (URISyntaxException ex) {
throw new IllegalStateException(ex);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,11 +24,13 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.web.Person;
import org.springframework.test.web.client.ExpectedCount;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.client.AsyncRestTemplate;
import static org.junit.Assert.*;
import static org.springframework.test.web.client.ExpectedCount.manyTimes;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;
@@ -63,7 +65,8 @@ public class SampleAsyncTests {
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
@SuppressWarnings("unused")
ListenableFuture<ResponseEntity<Person>> ludwig = restTemplate.getForEntity("/composers/{id}", Person.class, 42);
ListenableFuture<ResponseEntity<Person>> ludwig =
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
// We are only validating the request. The response is mocked out.
// person.getName().equals("Ludwig van Beethoven")
@@ -73,19 +76,26 @@ public class SampleAsyncTests {
}
@Test
public void performGetAsync() throws Exception {
public void performGetManyTimes() throws Exception {
String responseBody = "{\"name\" : \"Ludwig van Beethoven\", \"someDouble\" : \"1.6035\"}";
this.mockServer.expect(requestTo("/composers/42")).andExpect(method(HttpMethod.GET))
this.mockServer.expect(manyTimes(), requestTo("/composers/42")).andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
@SuppressWarnings("unused")
ListenableFuture<ResponseEntity<Person>> ludwig = restTemplate.getForEntity("/composers/{id}", Person.class, 42);
ListenableFuture<ResponseEntity<Person>> ludwig =
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
// We are only validating the request. The response is mocked out.
// person.getName().equals("Ludwig van Beethoven")
// person.getDouble().equals(1.6035)
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
this.mockServer.verify();
}
@@ -98,7 +108,8 @@ public class SampleAsyncTests {
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
@SuppressWarnings("unused")
ListenableFuture<ResponseEntity<Person>> ludwig = restTemplate.getForEntity("/composers/{id}", Person.class, 42);
ListenableFuture<ResponseEntity<Person>> ludwig =
this.restTemplate.getForEntity("/composers/{id}", Person.class, 42);
// hotel.getId() == 42
// hotel.getName().equals("Holiday Inn")
@@ -132,7 +143,7 @@ public class SampleAsyncTests {
this.mockServer.verify();
}
catch (AssertionError error) {
assertTrue(error.getMessage(), error.getMessage().contains("2 out of 4 were executed"));
assertTrue(error.getMessage(), error.getMessage().contains("2 unsatisfied expectation(s)"));
}
}
}

View File

@@ -23,10 +23,12 @@ 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;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.client.ExpectedCount.manyTimes;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@@ -60,7 +62,7 @@ public class SampleTests {
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
@SuppressWarnings("unused")
Person ludwig = restTemplate.getForObject("/composers/{id}", Person.class, 42);
Person ludwig = this.restTemplate.getForObject("/composers/{id}", Person.class, 42);
// We are only validating the request. The response is mocked out.
// hotel.getId() == 42
@@ -69,6 +71,28 @@ public class SampleTests {
this.mockServer.verify();
}
@Test
public void performGetManyTimes() throws Exception {
String responseBody = "{\"name\" : \"Ludwig van Beethoven\", \"someDouble\" : \"1.6035\"}";
this.mockServer.expect(manyTimes(), requestTo("/composers/42")).andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
@SuppressWarnings("unused")
Person ludwig = this.restTemplate.getForObject("/composers/{id}", Person.class, 42);
// We are only validating the request. The response is mocked out.
// hotel.getId() == 42
// hotel.getName().equals("Holiday Inn")
this.restTemplate.getForObject("/composers/{id}", Person.class, 42);
this.restTemplate.getForObject("/composers/{id}", Person.class, 42);
this.restTemplate.getForObject("/composers/{id}", Person.class, 42);
this.mockServer.verify();
}
@Test
public void performGetWithResponseBodyFromFile() throws Exception {
@@ -78,7 +102,7 @@ public class SampleTests {
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
@SuppressWarnings("unused")
Person ludwig = restTemplate.getForObject("/composers/{id}", Person.class, 42);
Person ludwig = this.restTemplate.getForObject("/composers/{id}", Person.class, 42);
// hotel.getId() == 42
// hotel.getName().equals("Holiday Inn")
@@ -112,7 +136,7 @@ public class SampleTests {
this.mockServer.verify();
}
catch (AssertionError error) {
assertTrue(error.getMessage(), error.getMessage().contains("2 out of 4 were executed"));
assertTrue(error.getMessage(), error.getMessage().contains("2 unsatisfied expectation(s)"));
}
}
}