From 4d310f0d5a9bfe3159af7a3fe80d5931353d00b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Sat, 16 Jun 2018 06:42:32 -0500 Subject: [PATCH 1/2] Add support for multiple REST Docs configuration customizers This commit introduces support for multiple configuration customizers for REST Docs with MockMvc, WebTestClient, and REST Assured. Closes gh-13498 --- .../restdocs/RestDocsAutoConfiguration.java | 32 +++--- ...AdvancedConfigurationIntegrationTests.java | 15 +++ ...AdvancedConfigurationIntegrationTests.java | 15 +++ ...AdvancedConfigurationIntegrationTests.java | 99 +++++++++++++++++++ 4 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java index f74227a696..03ff7808e6 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.test.autoconfigure.restdocs; +import java.util.List; + import io.restassured.builder.RequestSpecBuilder; import io.restassured.specification.RequestSpecification; @@ -58,14 +60,16 @@ public class RestDocsAutoConfiguration { @Bean @ConditionalOnMissingBean public MockMvcRestDocumentationConfigurer restDocsMockMvcConfigurer( - ObjectProvider configurationCustomizerProvider, + ObjectProvider> configurationCustomizerProvider, RestDocumentationContextProvider contextProvider) { MockMvcRestDocumentationConfigurer configurer = MockMvcRestDocumentation .documentationConfiguration(contextProvider); - RestDocsMockMvcConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider + List configurationCustomizers = configurationCustomizerProvider .getIfAvailable(); - if (configurationCustomizer != null) { - configurationCustomizer.customize(configurer); + if (configurationCustomizers != null) { + configurationCustomizers + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); } return configurer; } @@ -90,14 +94,16 @@ public class RestDocsAutoConfiguration { @Bean @ConditionalOnMissingBean public RequestSpecification restDocsRestAssuredConfigurer( - ObjectProvider configurationCustomizerProvider, + ObjectProvider> configurationCustomizerProvider, RestDocumentationContextProvider contextProvider) { RestAssuredRestDocumentationConfigurer configurer = RestAssuredRestDocumentation .documentationConfiguration(contextProvider); - RestDocsRestAssuredConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider + List configurationCustomizers = configurationCustomizerProvider .getIfAvailable(); - if (configurationCustomizer != null) { - configurationCustomizer.customize(configurer); + if (configurationCustomizers != null) { + configurationCustomizers + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); } return new RequestSpecBuilder().addFilter(configurer).build(); } @@ -119,14 +125,16 @@ public class RestDocsAutoConfiguration { @Bean @ConditionalOnMissingBean public WebTestClientRestDocumentationConfigurer restDocsWebTestClientConfigurer( - ObjectProvider configurationCustomizerProvider, + ObjectProvider> configurationCustomizerProvider, RestDocumentationContextProvider contextProvider) { WebTestClientRestDocumentationConfigurer configurer = WebTestClientRestDocumentation .documentationConfiguration(contextProvider); - RestDocsWebTestClientConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider + List configurationCustomizers = configurationCustomizerProvider .getIfAvailable(); - if (configurationCustomizer != null) { - configurationCustomizer.customize(configurer); + if (configurationCustomizers != null) { + configurationCustomizers + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); } return configurer; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 6c34911ccd..35522678a2 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -38,6 +38,8 @@ import org.springframework.util.FileSystemUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; /** @@ -72,6 +74,7 @@ public class MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTes assertThat(new File(defaultSnippetsDir, "curl-request.md")) .has(contentContaining("'http://localhost:8080/'")); assertThat(new File(defaultSnippetsDir, "links.md")).isFile(); + assertThat(new File(defaultSnippetsDir, "response-fields.md")).isFile(); } private Condition contentContaining(String toContain) { @@ -94,4 +97,16 @@ public class MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTes } + @TestConfiguration + public static class CustomizationConfiguration2 + implements RestDocsMockMvcConfigurationCustomizer { + + @Override + public void customize(MockMvcRestDocumentationConfigurer configurer) { + configurer.snippets().withAdditionalDefaults( + responseFields(fieldWithPath("_links.self").description("Main URL"))); + } + + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index a23ab806e2..ec197cf889 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -39,6 +39,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.document; /** @@ -77,6 +79,7 @@ public class RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegratio assertThat(new File(defaultSnippetsDir, "http-request.md")) .has(contentContaining("api.example.com")); assertThat(new File(defaultSnippetsDir, "http-response.md")).isFile(); + assertThat(new File(defaultSnippetsDir, "response-fields.md")).isFile(); } private Condition contentContaining(String toContain) { @@ -94,4 +97,16 @@ public class RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegratio } + @TestConfiguration + public static class CustomizationConfiguration2 + implements RestDocsRestAssuredConfigurationCustomizer { + + @Override + public void customize(RestAssuredRestDocumentationConfigurer configurer) { + configurer.snippets().withAdditionalDefaults( + responseFields(fieldWithPath("_links.self").description("Main URL"))); + } + + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java new file mode 100644 index 0000000000..68cd9cb961 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2012-2018 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.boot.test.autoconfigure.restdocs; + +import java.io.File; + +import org.assertj.core.api.Condition; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.restdocs.templates.TemplateFormats; +import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.util.FileSystemUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document; + +/** + * Integration tests for {@link RestDocsAutoConfiguration} with {@link WebTestClient}. + * + * @author Eddú Meléndez + */ +@RunWith(SpringRunner.class) +@WebFluxTest +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443) +public class WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests { + + @Before + public void deleteSnippets() { + FileSystemUtils.deleteRecursively(new File("target/generated-snippets")); + } + + @Autowired + private WebTestClient webTestClient; + + @Test + public void defaultSnippetsAreWritten() throws Exception { + this.webTestClient.get().uri("/").exchange().expectBody() + .consumeWith(document("default-snippets")); + File defaultSnippetsDir = new File("target/generated-snippets/default-snippets"); + assertThat(defaultSnippetsDir).exists(); + assertThat(new File(defaultSnippetsDir, "curl-request.md")) + .has(contentContaining("'https://api.example.com/'")); + assertThat(new File(defaultSnippetsDir, "http-request.md")) + .has(contentContaining("api.example.com")); + assertThat(new File(defaultSnippetsDir, "http-response.md")).isFile(); + assertThat(new File(defaultSnippetsDir, "response-fields.md")).isFile(); + } + + private Condition contentContaining(String toContain) { + return new ContentContainingCondition(toContain); + } + + @TestConfiguration + public static class CustomizationConfiguration + implements RestDocsWebTestClientConfigurationCustomizer { + + @Override + public void customize(WebTestClientRestDocumentationConfigurer configurer) { + configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + } + + } + + @TestConfiguration + public static class CustomizationConfiguration2 + implements RestDocsWebTestClientConfigurationCustomizer { + + @Override + public void customize(WebTestClientRestDocumentationConfigurer configurer) { + configurer.snippets().withAdditionalDefaults( + responseFields(fieldWithPath("_links.self").description("Main URL"))); + } + + } + +} From f10377bdb7a8209edd289f6472487efaadf72b50 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 16 Aug 2018 09:46:04 +0100 Subject: [PATCH 2/2] Polish "Add support for multiple REST Docs configuration customizers" Closes gh-13498 --- ...AdvancedConfigurationIntegrationTests.java | 26 +++++++---------- ...AdvancedConfigurationIntegrationTests.java | 29 ++++++++++--------- ...AdvancedConfigurationIntegrationTests.java | 29 ++++++++++--------- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 35522678a2..315111744a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -28,7 +28,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer; import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; import org.springframework.test.context.junit4.SpringRunner; @@ -47,6 +46,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder * MVC. * * @author Andy Wilkinson + * @author Eddú Meléndez */ @RunWith(SpringRunner.class) @WebMvcTest(controllers = RestDocsTestController.class, secure = false) @@ -82,28 +82,22 @@ public class MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTes } @TestConfiguration - public static class CustomizationConfiguration - implements RestDocsMockMvcConfigurationCustomizer { + public static class CustomizationConfiguration { @Bean public RestDocumentationResultHandler restDocumentation() { return MockMvcRestDocumentation.document("{method-name}"); } - @Override - public void customize(MockMvcRestDocumentationConfigurer configurer) { - configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + @Bean + public RestDocsMockMvcConfigurationCustomizer templateFormatCustomizer() { + return (configurer) -> configurer.snippets() + .withTemplateFormat(TemplateFormats.markdown()); } - } - - @TestConfiguration - public static class CustomizationConfiguration2 - implements RestDocsMockMvcConfigurationCustomizer { - - @Override - public void customize(MockMvcRestDocumentationConfigurer configurer) { - configurer.snippets().withAdditionalDefaults( + @Bean + public RestDocsMockMvcConfigurationCustomizer defaultSnippetsCustomizer() { + return (configurer) -> configurer.snippets().withAdditionalDefaults( responseFields(fieldWithPath("_links.self").description("Main URL"))); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index ec197cf889..c4f1dd846f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -29,7 +29,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.restdocs.restassured3.RestAssuredRestDocumentationConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.FileSystemUtils; @@ -87,23 +89,22 @@ public class RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegratio } @TestConfiguration - public static class CustomizationConfiguration - implements RestDocsRestAssuredConfigurationCustomizer { + public static class CustomizationConfiguration { - @Override - public void customize(RestAssuredRestDocumentationConfigurer configurer) { - configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + @Bean + public RestDocumentationResultHandler restDocumentation() { + return MockMvcRestDocumentation.document("{method-name}"); } - } + @Bean + public RestDocsRestAssuredConfigurationCustomizer templateFormatCustomizer() { + return (configurer) -> configurer.snippets() + .withTemplateFormat(TemplateFormats.markdown()); + } - @TestConfiguration - public static class CustomizationConfiguration2 - implements RestDocsRestAssuredConfigurationCustomizer { - - @Override - public void customize(RestAssuredRestDocumentationConfigurer configurer) { - configurer.snippets().withAdditionalDefaults( + @Bean + public RestDocsRestAssuredConfigurationCustomizer defaultSnippetsCustomizer() { + return (configurer) -> configurer.snippets().withAdditionalDefaults( responseFields(fieldWithPath("_links.self").description("Main URL"))); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 68cd9cb961..8dbe16ae67 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -26,8 +26,10 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; -import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.FileSystemUtils; @@ -74,23 +76,22 @@ public class WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrat } @TestConfiguration - public static class CustomizationConfiguration - implements RestDocsWebTestClientConfigurationCustomizer { + public static class CustomizationConfiguration { - @Override - public void customize(WebTestClientRestDocumentationConfigurer configurer) { - configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + @Bean + public RestDocumentationResultHandler restDocumentation() { + return MockMvcRestDocumentation.document("{method-name}"); } - } + @Bean + public RestDocsWebTestClientConfigurationCustomizer templateFormatCustomizer() { + return (configurer) -> configurer.snippets() + .withTemplateFormat(TemplateFormats.markdown()); + } - @TestConfiguration - public static class CustomizationConfiguration2 - implements RestDocsWebTestClientConfigurationCustomizer { - - @Override - public void customize(WebTestClientRestDocumentationConfigurer configurer) { - configurer.snippets().withAdditionalDefaults( + @Bean + public RestDocsWebTestClientConfigurationCustomizer defaultSnippetsCustomizer() { + return (configurer) -> configurer.snippets().withAdditionalDefaults( responseFields(fieldWithPath("_links.self").description("Main URL"))); }