Add ExecutingResponseCreator

This commit adds a new `ResponseCreator` implementation that uses a
`ClientHttpRequestFactory` to perform an actual request.

Closes gh-29721
This commit is contained in:
Simon Baslé
2022-12-20 16:36:06 +01:00
committed by rstoyanchev
parent ae7cff35dc
commit 4bcc24372a
5 changed files with 300 additions and 0 deletions

View File

@@ -17,13 +17,22 @@
package org.springframework.test.web.client;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.test.web.client.MockRestServiceServer.MockRestServiceServerBuilder;
import org.springframework.test.web.client.response.ExecutingResponseCreator;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
@@ -88,6 +97,43 @@ class MockRestServiceServerTests {
server.verify();
}
@Test
void executingResponseCreator() {
RestTemplate restTemplateWithMockEcho = createEchoRestTemplate();
final ExecutingResponseCreator withActualCall = new ExecutingResponseCreator(restTemplateWithMockEcho.getRequestFactory());
MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplateWithMockEcho).build();
server.expect(requestTo("/profile")).andRespond(withSuccess());
server.expect(requestTo("/quoteOfTheDay")).andRespond(withActualCall);
var response1 = restTemplateWithMockEcho.getForEntity("/profile", String.class);
var response2 = restTemplateWithMockEcho.getForEntity("/quoteOfTheDay", String.class);
server.verify();
assertThat(response1.getStatusCode().value())
.as("response1 status").isEqualTo(200);
assertThat(response1.getBody())
.as("response1 body").isNullOrEmpty();
assertThat(response2.getStatusCode().value())
.as("response2 status").isEqualTo(300);
assertThat(response2.getBody())
.as("response2 body").isEqualTo("echo from /quoteOfTheDay");
}
private static RestTemplate createEchoRestTemplate() {
final ClientHttpRequestFactory echoRequestFactory = (uri, httpMethod) -> {
final MockClientHttpRequest req = new MockClientHttpRequest(httpMethod, uri);
String body = "echo from " + uri.getPath();
final ClientHttpResponse resp = new MockClientHttpResponse(body.getBytes(StandardCharsets.UTF_8),
// Instead of 200, we use a less-common status code on purpose
HttpStatus.MULTIPLE_CHOICES);
resp.getHeaders().setContentType(MediaType.TEXT_PLAIN);
req.setResponse(resp);
return req;
};
return new RestTemplate(echoRequestFactory);
}
@Test
void resetAndReuseServer() {
MockRestServiceServer server = MockRestServiceServer.bindTo(this.restTemplate).build();

View File

@@ -0,0 +1,124 @@
/*
* Copyright 2002-2023 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
*
* https://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.response;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.AbstractClientHttpRequest;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.mock.http.client.MockClientHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for the {@link ExecutingResponseCreator} implementation.
*
* @author Simon Baslé
*/
class ExecutingResponseCreatorTests {
@Test
void ensureRequestNotNull() {
final ExecutingResponseCreator responseCreator = new ExecutingResponseCreator((uri, method) -> null);
assertThatIllegalStateException()
.isThrownBy(() -> responseCreator.createResponse(null))
.withMessage("Request should be an instance of MockClientHttpRequest");
}
@Test
void ensureRequestIsMock() {
final ExecutingResponseCreator responseCreator = new ExecutingResponseCreator((uri, method) -> null);
ClientHttpRequest notAMockRequest = new AbstractClientHttpRequest() {
@Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
return null;
}
@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
return null;
}
@Override
public HttpMethod getMethod() {
return null;
}
@Override
public URI getURI() {
return null;
}
};
assertThatIllegalStateException()
.isThrownBy(() -> responseCreator.createResponse(notAMockRequest))
.withMessage("Request should be an instance of MockClientHttpRequest");
}
@Test
void requestIsCopied() throws IOException {
MockClientHttpRequest originalRequest = new MockClientHttpRequest(HttpMethod.POST,
"https://example.org");
String body = "original body";
originalRequest.getHeaders().add("X-example", "original");
originalRequest.getBody().write(body.getBytes(StandardCharsets.UTF_8));
MockClientHttpResponse originalResponse = new MockClientHttpResponse(new byte[0], 500);
List<MockClientHttpRequest> factoryRequests = new ArrayList<>();
ClientHttpRequestFactory originalFactory = (uri, httpMethod) -> {
MockClientHttpRequest request = new MockClientHttpRequest(httpMethod, uri);
request.setResponse(originalResponse);
factoryRequests.add(request);
return request;
};
final ExecutingResponseCreator responseCreator = new ExecutingResponseCreator(originalFactory);
final ClientHttpResponse response = responseCreator.createResponse(originalRequest);
assertThat(response).as("response").isSameAs(originalResponse);
assertThat(originalRequest.isExecuted()).as("originalRequest.isExecuted").isFalse();
assertThat(factoryRequests)
.hasSize(1)
.first()
.isNotSameAs(originalRequest)
.satisfies(copiedRequest -> {
assertThat(copiedRequest)
.as("copied request")
.isNotSameAs(originalRequest);
assertThat(copiedRequest.isExecuted())
.as("copiedRequest.isExecuted").isTrue();
assertThat(copiedRequest.getBody())
.as("copiedRequest.body").isNotSameAs(originalRequest.getBody());
assertThat(copiedRequest.getHeaders())
.as("copiedRequest.headers").isNotSameAs(originalRequest.getHeaders());
});
}
}