Skip to content

Commit 862ffee

Browse files
committed
Update RestTestClient ExchangeResult
to expose request and URI template information and to have toString See gh-34428
1 parent 34f2597 commit 862ffee

File tree

5 files changed

+104
-10
lines changed

5 files changed

+104
-10
lines changed

spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ private class DefaultRequestBodyUriSpec implements RequestBodyUriSpec {
118118

119119
private final RestClient.RequestBodyUriSpec requestHeadersUriSpec;
120120

121+
private @Nullable String uriTemplate;
122+
121123
DefaultRequestBodyUriSpec(RestClient.RequestBodyUriSpec spec) {
122124
this.requestHeadersUriSpec = spec;
123125
String requestId = String.valueOf(requestIndex.incrementAndGet());
@@ -126,24 +128,28 @@ private class DefaultRequestBodyUriSpec implements RequestBodyUriSpec {
126128

127129
@Override
128130
public RequestBodySpec uri(String uriTemplate, @Nullable Object... uriVariables) {
131+
this.uriTemplate = uriTemplate;
129132
this.requestHeadersUriSpec.uri(uriTemplate, uriVariables);
130133
return this;
131134
}
132135

133136
@Override
134137
public RequestBodySpec uri(String uri, Map<String, ?> uriVariables) {
138+
this.uriTemplate = uri;
135139
this.requestHeadersUriSpec.uri(uri, uriVariables);
136140
return this;
137141
}
138142

139143
@Override
140144
public RequestBodySpec uri(Function<UriBuilder, URI> uriFunction) {
145+
this.uriTemplate = null;
141146
this.requestHeadersUriSpec.uri(uriFunction);
142147
return this;
143148
}
144149

145150
@Override
146151
public RequestBodySpec uri(URI uri) {
152+
this.uriTemplate = null;
147153
this.requestHeadersUriSpec.uri(uri);
148154
return this;
149155
}
@@ -229,8 +235,8 @@ public RequestHeadersSpec<?> body(Object body) {
229235
@Override
230236
public ResponseSpec exchange() {
231237
return new DefaultResponseSpec(
232-
this.requestHeadersUriSpec.exchangeForRequiredValue(
233-
(request, response) -> new ExchangeResult(response), false));
238+
this.requestHeadersUriSpec.exchangeForRequiredValue((request, response) ->
239+
new ExchangeResult(request, response, this.uriTemplate), false));
234240
}
235241
}
236242

spring-test/src/main/java/org/springframework/test/web/servlet/client/ExchangeResult.java

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,22 @@
1818

1919
import java.io.IOException;
2020
import java.net.HttpCookie;
21+
import java.net.URI;
2122
import java.util.List;
2223
import java.util.Optional;
2324
import java.util.regex.Matcher;
2425
import java.util.regex.Pattern;
26+
import java.util.stream.Collectors;
2527

2628
import org.apache.commons.logging.Log;
2729
import org.apache.commons.logging.LogFactory;
2830
import org.jspecify.annotations.Nullable;
2931

3032
import org.springframework.core.ParameterizedTypeReference;
3133
import org.springframework.http.HttpHeaders;
34+
import org.springframework.http.HttpMethod;
35+
import org.springframework.http.HttpRequest;
36+
import org.springframework.http.HttpStatus;
3237
import org.springframework.http.HttpStatusCode;
3338
import org.springframework.http.ResponseCookie;
3439
import org.springframework.util.Assert;
@@ -54,23 +59,60 @@ public class ExchangeResult {
5459
private static final Log logger = LogFactory.getLog(ExchangeResult.class);
5560

5661

62+
private final HttpRequest request;
63+
5764
private final ConvertibleClientHttpResponse clientResponse;
5865

66+
private final @Nullable String uriTemplate;
67+
5968
/** Ensure single logging; for example, for expectAll. */
6069
private boolean diagnosticsLogged;
6170

6271

63-
ExchangeResult(@Nullable ConvertibleClientHttpResponse response) {
64-
Assert.notNull(response, "Response must not be null");
72+
ExchangeResult(
73+
HttpRequest request, ConvertibleClientHttpResponse response, @Nullable String uriTemplate) {
74+
75+
Assert.notNull(request, "HttpRequest must not be null");
76+
Assert.notNull(response, "ClientHttpResponse must not be null");
77+
this.request = request;
6578
this.clientResponse = response;
79+
this.uriTemplate = uriTemplate;
6680
}
6781

6882
ExchangeResult(ExchangeResult result) {
69-
this(result.clientResponse);
83+
this(result.request, result.clientResponse, result.uriTemplate);
7084
this.diagnosticsLogged = result.diagnosticsLogged;
7185
}
7286

7387

88+
/**
89+
* Return the method of the request.
90+
*/
91+
public HttpMethod getMethod() {
92+
return this.request.getMethod();
93+
}
94+
95+
/**
96+
* Return the URI of the request.
97+
*/
98+
public URI getUrl() {
99+
return this.request.getURI();
100+
}
101+
102+
/**
103+
* Return the original URI template used to prepare the request, if any.
104+
*/
105+
public @Nullable String getUriTemplate() {
106+
return this.uriTemplate;
107+
}
108+
109+
/**
110+
* Return the request headers sent to the server.
111+
*/
112+
public HttpHeaders getRequestHeaders() {
113+
return this.request.getHeaders();
114+
}
115+
74116
/**
75117
* Return the HTTP status code as an {@link HttpStatusCode} value.
76118
*/
@@ -146,4 +188,28 @@ public void assertWithDiagnostics(Runnable assertion) {
146188
}
147189
}
148190

191+
@Override
192+
public String toString() {
193+
return "\n" +
194+
"> " + getMethod() + " " + getUrl() + "\n" +
195+
"> " + formatHeaders(getRequestHeaders(), "\n> ") + "\n" +
196+
"\n" +
197+
"< " + formatStatus(getStatus()) + "\n" +
198+
"< " + formatHeaders(getResponseHeaders(), "\n< ") + "\n";
199+
}
200+
201+
private String formatStatus(HttpStatusCode statusCode) {
202+
String result = statusCode.toString();
203+
if (statusCode instanceof HttpStatus status) {
204+
result += " " + status.getReasonPhrase();
205+
}
206+
return result;
207+
}
208+
209+
private String formatHeaders(HttpHeaders headers, String delimiter) {
210+
return headers.headerSet().stream()
211+
.map(entry -> entry.getKey() + ": " + entry.getValue())
212+
.collect(Collectors.joining(delimiter));
213+
}
214+
149215
}

spring-test/src/test/java/org/springframework/test/web/servlet/client/CookieAssertionsTests.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616

1717
package org.springframework.test.web.servlet.client;
1818

19+
import java.io.IOException;
1920
import java.time.Duration;
2021

22+
import org.junit.jupiter.api.BeforeEach;
2123
import org.junit.jupiter.api.Test;
2224

2325
import org.springframework.http.HttpHeaders;
26+
import org.springframework.http.HttpStatusCode;
2427
import org.springframework.http.ResponseCookie;
28+
import org.springframework.mock.http.client.MockClientHttpRequest;
2529
import org.springframework.web.client.RestClient;
2630

2731
import static org.assertj.core.api.Assertions.assertThat;
@@ -47,9 +51,14 @@ public class CookieAssertionsTests {
4751
.sameSite("Lax")
4852
.build();
4953

50-
private final CookieAssertions assertions = cookieAssertions(cookie);
54+
private CookieAssertions assertions;
5155

5256

57+
@BeforeEach
58+
void setUp() throws IOException {
59+
this.assertions = cookieAssertions(cookie);
60+
}
61+
5362
@Test
5463
void valueEquals() {
5564
assertions.valueEquals("foo", "bar");
@@ -135,12 +144,13 @@ void sameSite() {
135144
}
136145

137146

138-
private CookieAssertions cookieAssertions(ResponseCookie cookie) {
147+
private CookieAssertions cookieAssertions(ResponseCookie cookie) throws IOException {
139148
RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response = mock();
140149
var headers = new HttpHeaders();
141150
headers.set(HttpHeaders.SET_COOKIE, cookie.toString());
142151
when(response.getHeaders()).thenReturn(headers);
143-
ExchangeResult result = new ExchangeResult(response);
152+
when(response.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200));
153+
ExchangeResult result = new ExchangeResult(new MockClientHttpRequest(), response, null);
144154
return new CookieAssertions(result, mock());
145155
}
146156

spring-test/src/test/java/org/springframework/test/web/servlet/client/HeaderAssertionTests.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.test.web.servlet.client;
1818

19+
import java.io.IOException;
1920
import java.net.URI;
2021
import java.time.ZoneId;
2122
import java.time.ZonedDateTime;
@@ -26,7 +27,9 @@
2627
import org.springframework.http.CacheControl;
2728
import org.springframework.http.ContentDisposition;
2829
import org.springframework.http.HttpHeaders;
30+
import org.springframework.http.HttpStatusCode;
2931
import org.springframework.http.MediaType;
32+
import org.springframework.mock.http.client.MockClientHttpRequest;
3033
import org.springframework.web.client.RestClient;
3134

3235
import static org.assertj.core.api.Assertions.assertThat;
@@ -311,10 +314,16 @@ void equalsDate() {
311314
}
312315

313316
private HeaderAssertions headerAssertions(HttpHeaders responseHeaders) {
317+
try {
314318
RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response = mock();
319+
when(response.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200));
315320
when(response.getHeaders()).thenReturn(responseHeaders);
316-
ExchangeResult result = new ExchangeResult(response);
321+
ExchangeResult result = new ExchangeResult(new MockClientHttpRequest(), response, null);
317322
return new HeaderAssertions(result, mock());
323+
}
324+
catch (IOException ex) {
325+
throw new IllegalStateException(ex);
326+
}
318327
}
319328

320329
}

spring-test/src/test/java/org/springframework/test/web/servlet/client/StatusAssertionTests.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020

2121
import org.junit.jupiter.api.Test;
2222

23+
import org.springframework.http.HttpHeaders;
2324
import org.springframework.http.HttpStatus;
2425
import org.springframework.http.HttpStatusCode;
26+
import org.springframework.mock.http.client.MockClientHttpRequest;
2527
import org.springframework.web.client.RestClient;
2628

2729
import static org.assertj.core.api.Assertions.assertThat;
@@ -255,7 +257,8 @@ private StatusAssertions statusAssertions(int status) {
255257
try {
256258
RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response = mock();
257259
when(response.getStatusCode()).thenReturn(HttpStatusCode.valueOf(status));
258-
ExchangeResult result = new ExchangeResult(response);
260+
when(response.getHeaders()).thenReturn(new HttpHeaders());
261+
ExchangeResult result = new ExchangeResult(new MockClientHttpRequest(), response, null);
259262
return new StatusAssertions(result, mock());
260263
}
261264
catch (IOException ex) {

0 commit comments

Comments
 (0)