diff --git a/spring-boot-actuator-docs/pom.xml b/spring-boot-actuator-docs/pom.xml
index 2fdd0c8c13..6ef2498e11 100644
--- a/spring-boot-actuator-docs/pom.xml
+++ b/spring-boot-actuator-docs/pom.xml
@@ -29,6 +29,11 @@
spring-boot-test
provided
+
+ org.springframework.boot
+ spring-boot-test-autoconfigure
+ provided
+
ch.qos.logback
logback-classic
diff --git a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/EndpointDocumentation.java b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/EndpointDocumentation.java
index cb120a772f..a1e8005287 100644
--- a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/EndpointDocumentation.java
+++ b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/EndpointDocumentation.java
@@ -26,23 +26,19 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import javax.servlet.Filter;
-
import groovy.text.Template;
import groovy.text.TemplateEngine;
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
+import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringApplicationConfiguration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
-import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
@@ -50,12 +46,9 @@ import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.StringUtils;
-import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
-import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -65,40 +58,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@TestPropertySource(properties = { "spring.jackson.serialization.indent_output=true",
"endpoints.health.sensitive=true", "endpoints.actuator.enabled=false" })
@DirtiesContext
+@AutoConfigureRestDocs(EndpointDocumentation.RESTDOCS_OUTPUT_DIR)
+@AutoConfigureMockMvc
public class EndpointDocumentation {
- private static final String RESTDOCS_OUTPUT_DIR = "target/generated-snippets";
-
- @Rule
- public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
- RESTDOCS_OUTPUT_DIR);
-
- @Autowired
- private WebApplicationContext context;
+ static final String RESTDOCS_OUTPUT_DIR = "target/generated-snippets";
@Autowired
private MvcEndpoints mvcEndpoints;
- @Autowired
- @Qualifier("metricFilter")
- private Filter metricFilter;
-
- @Autowired
- @Qualifier("webRequestLoggingFilter")
- private Filter traceFilter;
-
@Autowired
private TemplateEngine templates;
+ @Autowired
private MockMvc mockMvc;
- @Before
- public void setUp() {
- this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
- .addFilters(this.metricFilter, this.traceFilter)
- .apply(documentationConfiguration(this.restDocumentation)).build();
- }
-
@Test
public void logfile() throws Exception {
this.mockMvc.perform(get("/logfile").accept(MediaType.TEXT_PLAIN))
diff --git a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HealthEndpointDocumentation.java b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HealthEndpointDocumentation.java
index 229b3fdb4f..be61c5934a 100644
--- a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HealthEndpointDocumentation.java
+++ b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HealthEndpointDocumentation.java
@@ -16,25 +16,21 @@
package org.springframework.boot.actuate.hypermedia;
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
-import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
-import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -44,23 +40,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@TestPropertySource(properties = { "spring.jackson.serialization.indent_output=true",
"endpoints.health.sensitive=false" })
@DirtiesContext
+@AutoConfigureMockMvc
+@AutoConfigureRestDocs("target/generated-snippets")
public class HealthEndpointDocumentation {
- @Rule
- public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
- "target/generated-snippets");
-
@Autowired
- private WebApplicationContext context;
-
private MockMvc mockMvc;
- @Before
- public void setUp() {
- this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
- .apply(documentationConfiguration(this.restDocumentation)).build();
- }
-
@Test
public void health() throws Exception {
this.mockMvc.perform(get("/health").accept(MediaType.APPLICATION_JSON))
diff --git a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HypermediaEndpointDocumentation.java b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HypermediaEndpointDocumentation.java
index c462ca281b..2ad906ae26 100644
--- a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HypermediaEndpointDocumentation.java
+++ b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/HypermediaEndpointDocumentation.java
@@ -16,25 +16,21 @@
package org.springframework.boot.actuate.hypermedia;
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
-import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
-import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -43,23 +39,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@WebAppConfiguration
@TestPropertySource(properties = "spring.jackson.serialization.indent_output=true")
@DirtiesContext
+@AutoConfigureMockMvc
+@AutoConfigureRestDocs("target/generated-snippets")
public class HypermediaEndpointDocumentation {
- @Rule
- public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
- "target/generated-snippets");
-
@Autowired
- private WebApplicationContext context;
-
private MockMvc mockMvc;
- @Before
- public void setUp() {
- this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
- .apply(documentationConfiguration(this.restDocumentation)).build();
- }
-
@Test
public void beans() throws Exception {
this.mockMvc.perform(get("/beans").accept(MediaType.APPLICATION_JSON))
diff --git a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/SpringBootHypermediaApplication.java b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/SpringBootHypermediaApplication.java
index f41bae3d71..330729d6cb 100644
--- a/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/SpringBootHypermediaApplication.java
+++ b/spring-boot-actuator-docs/src/restdoc/java/org/springframework/boot/actuate/hypermedia/SpringBootHypermediaApplication.java
@@ -21,9 +21,14 @@ import groovy.text.TemplateEngine;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
+import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+// Flyway must go first
@SpringBootApplication
+@Import({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class })
public class SpringBootHypermediaApplication {
@Bean
diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
index 1f83e68241..21dee932c9 100644
--- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -4744,6 +4744,84 @@ database you can use the `@AutoConfigureTestDatabase` annotation:
+[[boot-features-testing-spring-boot-applications-testing-autoconfigurd-rest-docs]]
+==== Auto-configured Spring REST Docs tests
+Test `@AutoConfigureRestDocs` annotation can be used if you want to use Spring REST Docs
+in your tests. It will automatically configure `MockMvc` to use Spring REST Docs and
+removes the need for Spring REST Docs' JUnit rule.
+
+[source,java,indent=0]
+----
+ import org.junit.Test;
+ import org.junit.runner.RunWith;
+
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+ import org.springframework.http.MediaType;
+ import org.springframework.test.context.junit4.SpringRunner;
+ import org.springframework.test.web.servlet.MockMvc;
+
+ import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
+ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+ @RunWith(SpringRunner.class)
+ @WebMvcTest(UserController.class)
+ @AutoConfigureRestDocs("target/generated-snippets")
+ public class UserDocumentationTests {
+
+ @Autowired
+ private MockMvc mvc;
+
+ @Test
+ public void listUsers() throws Exception {
+ this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
+ .andExpect(status().isOk())
+ .andDo(document("list-users"));
+ }
+
+ }
+----
+
+In addition to configuring the output directory, `@AutoConfigureRestDocs` can also
+configure the host, scheme, and port that will appear in any documented URIs. If you
+require more control over Spring REST Docs' configuration a
+`RestDocsMockMvcConfigurationCustomizer` bean can be used:
+
+[source,java,indent=0]
+----
+ @TestConfiguration
+ static class CustomizationConfiguration
+ implements RestDocsMockMvcConfigurationCustomizer {
+
+ @Override
+ public void customize(MockMvcRestDocumentationConfigurer configurer) {
+ configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
+ }
+
+ }
+----
+
+If you want to make use of Spring REST Docs' support for a parameterized output directory,
+you can create a `RestDocumentationResultHandler` bean. The auto-configuration will
+call `alwaysDo` with this result handler, thereby causing each `MockMvc` call to
+automatically generate the default snippets:
+
+[source,java,indent=0]
+----
+ @TestConfiguration
+ static class ResultHandlerConfiguration{
+
+ @Bean
+ public RestDocumentationResultHandler restDocumentation() {
+ return MockMvcRestDocumentation.document("{method-name}");
+ }
+
+ }
+----
+
+
+
[[boot-features-testing-spring-boot-applications-with-spock]]
==== Using Spock to test Spring Boot applications
If you wish to use Spock to test a Spring Boot application you should add a dependency
diff --git a/spring-boot-parent/src/checkstyle/checkstyle.xml b/spring-boot-parent/src/checkstyle/checkstyle.xml
index 61889c0536..32cc2a1bf1 100644
--- a/spring-boot-parent/src/checkstyle/checkstyle.xml
+++ b/spring-boot-parent/src/checkstyle/checkstyle.xml
@@ -71,7 +71,7 @@
+ value="org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo" />
diff --git a/spring-boot-test-autoconfigure/pom.xml b/spring-boot-test-autoconfigure/pom.xml
index c62b694785..c6a2edf7fb 100644
--- a/spring-boot-test-autoconfigure/pom.xml
+++ b/spring-boot-test-autoconfigure/pom.xml
@@ -96,20 +96,30 @@
true
+
+ org.springframework.restdocs
+ spring-restdocs-mockmvc
+ true
+
- org.aspectj
- aspectjrt
+ ch.qos.logback
+ logback-classic
+ test
+
+
+ com.h2database
+ h2
test
org.aspectj
- aspectjweaver
+ aspectjrt
test
- com.h2database
- h2
+ org.aspectj
+ aspectjweaver
test
@@ -123,8 +133,8 @@
test
- ch.qos.logback
- logback-classic
+ org.springframework.hateoas
+ spring-hateoas
test
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/AutoConfigureRestDocs.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/AutoConfigureRestDocs.java
new file mode 100644
index 0000000000..b2cbbb859b
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/AutoConfigureRestDocs.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.properties.PropertyMapping;
+import org.springframework.context.annotation.Import;
+
+/**
+ * Annotation that can be applied to a test class to enable and configure
+ * auto-configuration of Spring REST Docs. Allows configuration of the output directory
+ * and the host, scheme, and port of generated URIs. When further configuration is
+ * required a {@link RestDocsMockMvcConfigurationCustomizer} bean can be used.
+ *
+ * @author Andy Wilkinson
+ * @since 1.4.0
+ * @see RestDocsAutoConfiguration
+ * @see RestDocsMockMvcConfigurationCustomizer
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@ImportAutoConfiguration(RestDocsAutoConfiguration.class)
+@Import(RestDocumentationContextProviderRegistrar.class)
+@PropertyMapping("spring.test.restdocs")
+public @interface AutoConfigureRestDocs {
+
+ /**
+ * The output directory to which generated snippets will be written. A synonym for
+ * {@link #outputDir}.
+ * @return the output directory
+ */
+ String value() default "";
+
+ /**
+ * The output directory to which generated snippets will be written. A synonym for
+ * {@link #value}.
+ * @return the output directory
+ */
+ String outputDir() default "";
+
+ /**
+ * The scheme (typically {@code http} or {@code https}) to be used in documented URIs.
+ * Defaults to {@code http}.
+ * @return the scheme
+ */
+ String uriScheme() default "http";
+
+ /**
+ * The host to be used in documented URIs. Defaults to {@code localhost}.
+ * @return the host
+ */
+ String uriHost() default "localhost";
+
+ /**
+ * The port to be used in documented URIs. Defaults to {@code 8080}.
+ * @return the port
+ */
+ int uriPort() default 8080;
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java
new file mode 100644
index 0000000000..b1536c7336
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.restdocs.RestDocumentationContextProvider;
+import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
+import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
+import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Spring REST Docs.
+ *
+ * @author Andy Wilkinson
+ */
+@Configuration
+@ConditionalOnWebApplication
+@EnableConfigurationProperties
+class RestDocsAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(MockMvcRestDocumentationConfigurer.class)
+ public MockMvcRestDocumentationConfigurer restDocsMockMvcConfigurer(
+ ObjectProvider configurationCustomizerProvider,
+ RestDocumentationContextProvider contextProvider) {
+ MockMvcRestDocumentationConfigurer configurer = MockMvcRestDocumentation
+ .documentationConfiguration(contextProvider);
+ RestDocsMockMvcConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider
+ .getIfAvailable();
+ if (configurationCustomizer != null) {
+ configurationCustomizer.customize(configurer);
+ }
+ return configurer;
+ }
+
+ @Bean
+ @ConfigurationProperties("spring.test.restdocs")
+ public RestDocsMockMvcBuilderCustomizer restDocumentationConfigurer(
+ MockMvcRestDocumentationConfigurer configurer,
+ ObjectProvider resultHandler) {
+ return new RestDocsMockMvcBuilderCustomizer(configurer,
+ resultHandler.getIfAvailable());
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsMockMvcBuilderCustomizer.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsMockMvcBuilderCustomizer.java
new file mode 100644
index 0000000000..d0b2b91c7f
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsMockMvcBuilderCustomizer.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcBuilderCustomizer;
+import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
+import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
+import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
+import org.springframework.util.StringUtils;
+
+/**
+ * A {@link MockMvcBuilderCustomizer} that configures Spring REST Docs.
+ *
+ * @author Andy Wilkinson
+ */
+class RestDocsMockMvcBuilderCustomizer
+ implements InitializingBean, MockMvcBuilderCustomizer {
+
+ private final MockMvcRestDocumentationConfigurer delegate;
+
+ private final RestDocumentationResultHandler resultHandler;
+
+ private String uriScheme;
+
+ private String uriHost;
+
+ private Integer uriPort;
+
+ RestDocsMockMvcBuilderCustomizer(MockMvcRestDocumentationConfigurer delegate,
+ RestDocumentationResultHandler resultHandler) {
+ this.delegate = delegate;
+ this.resultHandler = resultHandler;
+ }
+
+ public String getUriScheme() {
+ return this.uriScheme;
+ }
+
+ public void setUriScheme(String uriScheme) {
+ this.uriScheme = uriScheme;
+ }
+
+ public String getUriHost() {
+ return this.uriHost;
+ }
+
+ public void setUriHost(String uriHost) {
+ this.uriHost = uriHost;
+ }
+
+ public Integer getUriPort() {
+ return this.uriPort;
+ }
+
+ public void setUriPort(Integer uriPort) {
+ this.uriPort = uriPort;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ if (StringUtils.hasText(this.uriScheme)) {
+ this.delegate.uris().withScheme(this.uriScheme);
+ }
+ if (StringUtils.hasText(this.uriHost)) {
+ this.delegate.uris().withHost(this.uriHost);
+ }
+ if (this.uriPort != null) {
+ this.delegate.uris().withPort(this.uriPort);
+ }
+ }
+
+ @Override
+ public void customize(ConfigurableMockMvcBuilder> builder) {
+ builder.apply(this.delegate);
+ if (this.resultHandler != null) {
+ builder.alwaysDo(this.resultHandler);
+ }
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsMockMvcConfigurationCustomizer.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsMockMvcConfigurationCustomizer.java
new file mode 100644
index 0000000000..928e160b34
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsMockMvcConfigurationCustomizer.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
+
+/**
+ * A customizer for {@link MockMvcRestDocumentationConfigurer}. If a
+ * {@code RestDocsMockMvcConfigurationCustomizer} bean is found in the application context
+ * it will be {@link #customize called} to customize the
+ * {@code MockMvcRestDocumentationConfigurer} before it is applied. Intended for use only
+ * when the attributes on {@link AutoConfigureRestDocs} do not provide sufficient
+ * customization.
+ *
+ * @author Andy Wilkinson
+ * @since 1.4.0
+ */
+public interface RestDocsMockMvcConfigurationCustomizer {
+
+ /**
+ * Customize the given {@configurer}.
+ * @param configurer the configurer
+ */
+ void customize(MockMvcRestDocumentationConfigurer configurer);
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestExecutionListener.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestExecutionListener.java
new file mode 100644
index 0000000000..0c8fb183c5
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestExecutionListener.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.restdocs.ManualRestDocumentation;
+import org.springframework.test.context.TestContext;
+import org.springframework.test.context.TestExecutionListener;
+import org.springframework.test.context.support.AbstractTestExecutionListener;
+import org.springframework.util.ClassUtils;
+
+/**
+ * A {@link TestExecutionListener} for Spring REST Docs that removes the need for a
+ * @Rule
when using JUnit or manual before and after test calls when using
+ * TestNG.
+ *
+ * @author Andy Wilkinson
+ * @since 1.4.0
+ */
+public class RestDocsTestExecutionListener extends AbstractTestExecutionListener {
+
+ private static final String REST_DOCS_CLASS = "org.springframework.restdocs.ManualRestDocumentation";
+
+ @Override
+ public void beforeTestMethod(TestContext testContext) throws Exception {
+ if (restDocsIsPresent()) {
+ new DocumentationHandler().beforeTestMethod(testContext);
+ }
+ }
+
+ @Override
+ public void afterTestMethod(TestContext testContext) throws Exception {
+ if (restDocsIsPresent()) {
+ new DocumentationHandler().afterTestMethod(testContext);
+ }
+ }
+
+ private boolean restDocsIsPresent() {
+ return ClassUtils.isPresent(REST_DOCS_CLASS, getClass().getClassLoader());
+ }
+
+ private static class DocumentationHandler {
+
+ private void beforeTestMethod(TestContext testContext) throws Exception {
+ ManualRestDocumentation restDocumentation = findManualRestDocumentation(
+ testContext);
+ if (restDocumentation != null) {
+ restDocumentation.beforeTest(testContext.getTestClass(),
+ testContext.getTestMethod().getName());
+ }
+ }
+
+ private void afterTestMethod(TestContext testContext) {
+ ManualRestDocumentation restDocumentation = findManualRestDocumentation(
+ testContext);
+ if (restDocumentation != null) {
+ restDocumentation.afterTest();
+ }
+ }
+
+ private ManualRestDocumentation findManualRestDocumentation(
+ TestContext testContext) {
+ try {
+ return testContext.getApplicationContext()
+ .getBean(ManualRestDocumentation.class);
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ return null;
+ }
+ }
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocumentationContextProviderRegistrar.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocumentationContextProviderRegistrar.java
new file mode 100644
index 0000000000..0963da774a
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocumentationContextProviderRegistrar.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.restdocs.ManualRestDocumentation;
+import org.springframework.util.StringUtils;
+
+/**
+ * {@link ImportBeanDefinitionRegistrar} used by {@link AutoConfigureRestDocs}.
+ *
+ * @author Andy Wilkinson
+ */
+class RestDocumentationContextProviderRegistrar implements ImportBeanDefinitionRegistrar {
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ BeanDefinitionRegistry registry) {
+ AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
+ .genericBeanDefinition(ManualRestDocumentation.class)
+ .addConstructorArgValue(determineOutputDir(importingClassMetadata))
+ .getBeanDefinition();
+ registry.registerBeanDefinition(ManualRestDocumentation.class.getName(),
+ beanDefinition);
+ }
+
+ private String determineOutputDir(AnnotationMetadata annotationMetadata) {
+ Map annotationAttributes = annotationMetadata
+ .getAnnotationAttributes(AutoConfigureRestDocs.class.getName());
+ String outputDir = (String) annotationAttributes.get("outputDir");
+ if (!StringUtils.hasText(outputDir)) {
+ outputDir = (String) annotationAttributes.get("value");
+ if (!StringUtils.hasText(outputDir)) {
+ throw new IllegalStateException(
+ "Either value or outputDir must be specified on @AutoConfigureRestDocs");
+ }
+ }
+ return outputDir;
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories
index 136c97df4e..03cd4eaee3 100644
--- a/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -7,4 +7,5 @@ org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCus
# Test Execution Listeners
org.springframework.test.context.TestExecutionListener=\
org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener,\
-org.springframework.boot.test.autoconfigure.json.JsonTesterInitializationTestExecutionListener
+org.springframework.boot.test.autoconfigure.json.JsonTesterInitializationTestExecutionListener,\
+org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/ContentContainingCondition.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/ContentContainingCondition.java
new file mode 100644
index 0000000000..551b710fa5
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/ContentContainingCondition.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+import org.assertj.core.api.Condition;
+import org.assertj.core.description.TextDescription;
+
+import org.springframework.util.FileCopyUtils;
+
+/**
+ * A {@link Condition} to assert that a file's contents contain a given string.
+ *
+ * @author Andy Wilkinson
+ */
+class ContentContainingCondition extends Condition {
+
+ private final String toContain;
+
+ ContentContainingCondition(String toContain) {
+ super(new TextDescription("content containing %s", toContain));
+ this.toContain = toContain;
+ }
+
+ @Override
+ public boolean matches(File value) {
+ Reader reader = null;
+ try {
+ reader = new FileReader(value);
+ String content = FileCopyUtils.copyToString(new FileReader(value));
+ System.out.println(content);
+ return content.contains(this.toContain);
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ }
+ catch (IOException ex) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java
new file mode 100644
index 0000000000..ac32427b64
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012-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.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.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;
+import org.springframework.test.web.servlet.MockMvc;
+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.test.web.servlet.request.MockMvcRequestBuilders.get;
+
+/**
+ * @author Andy Wilkinson
+ */
+@RunWith(SpringRunner.class)
+@WebMvcTest(RestDocsTestController.class)
+@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
+public class RestDocsAutoConfigurationAdvancedConfigurationIntegrationTests {
+
+ @Before
+ public void deleteSnippets() {
+ FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
+ }
+
+ @Autowired
+ private MockMvc mvc;
+
+ @Autowired
+ private RestDocumentationResultHandler document;
+
+ @Test
+ public void snippetGeneration() throws Exception {
+ this.document.snippets(links(
+ linkWithRel("self").description("Canonical location of this resource")));
+ this.mvc.perform(get("/"));
+ File defaultSnippetsDir = new File(
+ "target/generated-snippets/snippet-generation");
+ assertThat(defaultSnippetsDir).exists();
+ assertThat(new File(defaultSnippetsDir, "curl-request.md"))
+ .has(contentContaining("'http://localhost:8080/'"));
+ assertThat(new File(defaultSnippetsDir, "links.md")).isFile();
+ }
+
+ private Condition contentContaining(String toContain) {
+ return new ContentContainingCondition(toContain);
+ }
+
+ @TestConfiguration
+ public static class CustomizationConfiguration
+ implements RestDocsMockMvcConfigurationCustomizer {
+
+ @Bean
+ public RestDocumentationResultHandler restDocumentation() {
+ return MockMvcRestDocumentation.document("{method-name}");
+ }
+
+ @Override
+ public void customize(MockMvcRestDocumentationConfigurer configurer) {
+ configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
+ }
+
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfigurationIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfigurationIntegrationTests.java
new file mode 100644
index 0000000000..e349425609
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfigurationIntegrationTests.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-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.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.servlet.WebMvcTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.util.FileSystemUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+
+/**
+ * Tests for {@link RestDocsAutoConfiguration}.
+ *
+ * @author Andy Wilkinson
+ */
+@RunWith(SpringRunner.class)
+@WebMvcTest
+@AutoConfigureRestDocs(outputDir = "target/generated-snippets", uriScheme = "https", uriHost = "api.example.com", uriPort = 443)
+public class RestDocsAutoConfigurationIntegrationTests {
+
+ @Before
+ public void deleteSnippets() {
+ FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
+ }
+
+ @Autowired
+ private MockMvc mvc;
+
+ @Test
+ public void defaultSnippetsAreWritten() throws Exception {
+ this.mvc.perform(get("/")).andDo(document("default-snippets"));
+ File defaultSnippetsDir = new File("target/generated-snippets/default-snippets");
+ assertThat(defaultSnippetsDir).exists();
+ assertThat(new File(defaultSnippetsDir, "curl-request.adoc"))
+ .has(contentContaining("'https://api.example.com/'"));
+ assertThat(new File(defaultSnippetsDir, "http-request.adoc"))
+ .has(contentContaining("api.example.com"));
+ assertThat(new File(defaultSnippetsDir, "http-response.adoc")).isFile();
+ }
+
+ private Condition contentContaining(String toContain) {
+ return new ContentContainingCondition(toContain);
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestApplication.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestApplication.java
new file mode 100644
index 0000000000..eef3c6095f
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Test application used with {@link AutoConfigureRestDocs} tests.
+ *
+ * @author Andy Wilkinson
+ */
+@SpringBootApplication
+public class RestDocsTestApplication {
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestController.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestController.java
new file mode 100644
index 0000000000..3fa6120c39
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsTestController.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012-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.boot.test.autoconfigure.restdocs;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.hateoas.MediaTypes;
+import org.springframework.hateoas.mvc.ControllerLinkBuilder;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class RestDocsTestController {
+
+ @ResponseBody
+ @RequestMapping(path = "/", produces = MediaTypes.HAL_JSON_VALUE)
+ public Map index() {
+ Map response = new HashMap();
+ Map links = new HashMap();
+ links.put("self", ControllerLinkBuilder.linkTo(getClass()).toUri().toString());
+ response.put("_links", links);
+ return response;
+ }
+
+}