Skip to content

Commit 094e653

Browse files
committed
Versioning support in WebTestClient controller setup
See gh-34919
1 parent 3095219 commit 094e653

File tree

4 files changed

+62
-17
lines changed

4 files changed

+62
-17
lines changed

spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultControllerSpec.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
import org.springframework.util.ObjectUtils;
3232
import org.springframework.validation.Validator;
3333
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
34+
import org.springframework.web.reactive.config.ApiVersionConfigurer;
3435
import org.springframework.web.reactive.config.BlockingExecutionConfigurer;
3536
import org.springframework.web.reactive.config.CorsRegistry;
3637
import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration;
@@ -118,6 +119,12 @@ public DefaultControllerSpec validator(Validator validator) {
118119
return this;
119120
}
120121

122+
@Override
123+
public WebTestClient.ControllerSpec apiVersioning(Consumer<ApiVersionConfigurer> configurer) {
124+
this.configurer.versionConsumer = configurer;
125+
return this;
126+
}
127+
121128
@Override
122129
public DefaultControllerSpec viewResolvers(Consumer<ViewResolverRegistry> consumer) {
123130
this.configurer.viewResolversConsumer = consumer;
@@ -168,6 +175,8 @@ private static class TestWebFluxConfigurer implements WebFluxConfigurer {
168175

169176
private @Nullable Validator validator;
170177

178+
private @Nullable Consumer<ApiVersionConfigurer> versionConsumer;
179+
171180
private @Nullable Consumer<ViewResolverRegistry> viewResolversConsumer;
172181

173182
private @Nullable Consumer<BlockingExecutionConfigurer> executionConsumer;
@@ -219,6 +228,13 @@ public void addFormatters(FormatterRegistry registry) {
219228
return this.validator;
220229
}
221230

231+
@Override
232+
public void configureApiVersioning(ApiVersionConfigurer configurer) {
233+
if (this.versionConsumer != null) {
234+
this.versionConsumer.accept(configurer);
235+
}
236+
}
237+
222238
@Override
223239
public void configureViewResolvers(ViewResolverRegistry registry) {
224240
if (this.viewResolversConsumer != null) {

spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.springframework.web.client.ApiVersionFormatter;
4949
import org.springframework.web.client.ApiVersionInserter;
5050
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
51+
import org.springframework.web.reactive.config.ApiVersionConfigurer;
5152
import org.springframework.web.reactive.config.BlockingExecutionConfigurer;
5253
import org.springframework.web.reactive.config.CorsRegistry;
5354
import org.springframework.web.reactive.config.PathMatchConfigurer;
@@ -346,6 +347,12 @@ interface ControllerSpec extends MockServerSpec<ControllerSpec> {
346347
*/
347348
ControllerSpec validator(Validator validator);
348349

350+
/**
351+
* Configure API versioning for mapping requests to controller methods.
352+
* @since 7.0
353+
*/
354+
ControllerSpec apiVersioning(Consumer<ApiVersionConfigurer> configurer);
355+
349356
/**
350357
* Configure view resolution.
351358
* @see WebFluxConfigurer#configureViewResolvers

spring-test/src/test/java/org/springframework/test/web/reactive/server/DefaultControllerSpecTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
2828
import org.springframework.web.bind.annotation.GetMapping;
2929
import org.springframework.web.bind.annotation.RestController;
3030
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
31+
import org.springframework.web.reactive.config.ApiVersionConfigurer;
3132
import org.springframework.web.reactive.config.CorsRegistry;
3233
import org.springframework.web.reactive.config.PathMatchConfigurer;
3334
import org.springframework.web.reactive.config.ViewResolverRegistry;
@@ -87,6 +88,7 @@ public void configurerConsumers() {
8788
TestConsumer<FormatterRegistry> formatterConsumer = new TestConsumer<>();
8889
TestConsumer<ServerCodecConfigurer> codecsConsumer = new TestConsumer<>();
8990
TestConsumer<PathMatchConfigurer> pathMatchingConsumer = new TestConsumer<>();
91+
TestConsumer<ApiVersionConfigurer> versionConsumer = new TestConsumer<>();
9092
TestConsumer<ViewResolverRegistry> viewResolverConsumer = new TestConsumer<>();
9193

9294
new DefaultControllerSpec(new MyController())
@@ -96,6 +98,7 @@ public void configurerConsumers() {
9698
.formatters(formatterConsumer)
9799
.httpMessageCodecs(codecsConsumer)
98100
.pathMatching(pathMatchingConsumer)
101+
.apiVersioning(versionConsumer)
99102
.viewResolvers(viewResolverConsumer)
100103
.build();
101104

@@ -105,6 +108,7 @@ public void configurerConsumers() {
105108
assertThat(formatterConsumer.getValue()).isNotNull();
106109
assertThat(codecsConsumer.getValue()).isNotNull();
107110
assertThat(pathMatchingConsumer.getValue()).isNotNull();
111+
assertThat(versionConsumer.getValue()).isNotNull();
108112
assertThat(viewResolverConsumer.getValue()).isNotNull();
109113
}
110114

spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ApiVersionTests.java

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.net.URI;
2020
import java.util.Map;
21+
import java.util.function.Consumer;
2122

2223
import org.junit.jupiter.api.Test;
2324

@@ -26,6 +27,7 @@
2627
import org.springframework.web.bind.annotation.GetMapping;
2728
import org.springframework.web.bind.annotation.RestController;
2829
import org.springframework.web.client.ApiVersionInserter;
30+
import org.springframework.web.reactive.config.ApiVersionConfigurer;
2931

3032
import static org.assertj.core.api.Assertions.assertThat;
3133

@@ -36,35 +38,49 @@
3638
*/
3739
public class ApiVersionTests {
3840

39-
private static final String HEADER_NAME = "X-API-Version";
40-
41-
4241
@Test
4342
void header() {
44-
Map<String, String> result = performRequest(ApiVersionInserter.useHeader("X-API-Version"));
45-
assertThat(result.get(HEADER_NAME)).isEqualTo("1.2");
43+
String header = "X-API-Version";
44+
45+
Map<String, String> result = performRequest(
46+
configurer -> configurer.useRequestHeader(header),
47+
ApiVersionInserter.useHeader(header));
48+
49+
assertThat(result.get(header)).isEqualTo("1.2");
4650
}
4751

4852
@Test
4953
void queryParam() {
50-
Map<String, String> result = performRequest(ApiVersionInserter.useQueryParam("api-version"));
51-
assertThat(result.get("query")).isEqualTo("api-version=1.2");
54+
String param = "api-version";
55+
56+
Map<String, String> result = performRequest(
57+
configurer -> configurer.useRequestParam(param),
58+
ApiVersionInserter.useQueryParam(param));
59+
60+
assertThat(result.get("query")).isEqualTo(param + "=1.2");
5261
}
5362

5463
@Test
5564
void pathSegment() {
56-
Map<String, String> result = performRequest(ApiVersionInserter.usePathSegment(0));
65+
Map<String, String> result = performRequest(
66+
configurer -> configurer.usePathSegment(0),
67+
ApiVersionInserter.usePathSegment(0));
68+
5769
assertThat(result.get("path")).isEqualTo("/1.2/path");
5870
}
5971

6072
@SuppressWarnings("unchecked")
61-
private Map<String, String> performRequest(ApiVersionInserter inserter) {
62-
return WebTestClient.bindToController(new TestController())
73+
private Map<String, String> performRequest(
74+
Consumer<ApiVersionConfigurer> versionConfigurer, ApiVersionInserter inserter) {
75+
76+
WebTestClient client = WebTestClient.bindToController(new TestController())
77+
.apiVersioning(versionConfigurer)
6378
.configureClient()
6479
.baseUrl("/path")
6580
.apiVersionInserter(inserter)
66-
.build()
67-
.get()
81+
.build();
82+
83+
return client.get()
6884
.apiVersion(1.2)
6985
.exchange()
7086
.returnResult(Map.class)
@@ -76,14 +92,16 @@ private Map<String, String> performRequest(ApiVersionInserter inserter) {
7692
@RestController
7793
static class TestController {
7894

79-
@GetMapping("/**")
95+
private static final String HEADER = "X-API-Version";
96+
97+
@GetMapping(path = "/**", version = "1.2")
8098
Map<String, String> handle(ServerHttpRequest request) {
8199
URI uri = request.getURI();
82100
String query = uri.getQuery();
83-
String header = request.getHeaders().getFirst(HEADER_NAME);
101+
String versionHeader = request.getHeaders().getFirst(HEADER);
84102
return Map.of("path", uri.getRawPath(),
85103
"query", (query != null ? query : ""),
86-
HEADER_NAME, (header != null ? header : ""));
104+
HEADER, (versionHeader != null ? versionHeader : ""));
87105
}
88106
}
89107

0 commit comments

Comments
 (0)