Isolate and reduce Spring Test dependencies

This commit splits Spring REST Docs into two projects –
spring-restdocs-core and spring-restdocs-mockmvc.

spring-restdocs-core contains the vast majority of the code but does not
depend on a specific test framework other than JUnit. The use of a
Spring Test TestExecutionListener has been replaced with a JUnit test
rule. The rule is declared once per test class and configured with
the output directory to which the generated snippets should be written.
This simplifies the implementation as thread local storage is no longer
required to transfer information about the test that’s running into
Spring REST Docs. Instead, this transfer is now handled by the new test
rule. It has also simplified the configuration as it’s no longer
necessary for users to provide a system property that configures the
output directory.

spring-restdocs-mockmvc contains code that’s specific to using Spring
REST Docs with Spring MVC Test’s MockMvc. This is currently the only
testing framework that’s supported, but it paves the way for adding
support for additional frameworks. REST Assured is one that users seem
particularly interested in (see gh-80 and gh-102).

Closes gh-107
This commit is contained in:
Andy Wilkinson
2015-09-02 16:20:34 +01:00
parent 9d8bbf0558
commit 2b2b6fcd25
207 changed files with 1396 additions and 1425 deletions

View File

@@ -0,0 +1,236 @@
/*
* Copyright 2014-2015 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.restdocs.mockmvc;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasEntry;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.util.Arrays;
import javax.servlet.http.Part;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.mock.web.MockServletContext;
import org.springframework.restdocs.mockmvc.MockMvcOperationRequestFactory;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
/**
* Tests for {@link MockMvcOperationRequestFactory}
*
* @author Andy Wilkinson
*/
public class MockMvcOperationRequestFactoryTests {
private final MockMvcOperationRequestFactory factory = new MockMvcOperationRequestFactory();
@Test
public void httpRequest() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.get("/foo"));
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
}
@Test
public void httpRequestWithCustomPort() throws Exception {
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
.buildRequest(new MockServletContext());
mockRequest.setServerPort(8080);
OperationRequest request = this.factory.createOperationRequest(mockRequest);
assertThat(request.getUri(), is(URI.create("http://localhost:8080/foo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
}
@Test
public void requestWithContextPath() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders.get(
"/foo/bar").contextPath("/foo"));
assertThat(request.getUri(), is(URI.create("http://localhost/foo/bar")));
assertThat(request.getMethod(), is(HttpMethod.GET));
}
@Test
public void requestWithHeaders() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.get("/foo").header("a", "alpha", "apple").header("b", "bravo"));
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
assertThat(request.getHeaders(), hasEntry("a", Arrays.asList("alpha", "apple")));
assertThat(request.getHeaders(), hasEntry("b", Arrays.asList("bravo")));
}
@Test
public void httpsRequest() throws Exception {
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
.buildRequest(new MockServletContext());
mockRequest.setScheme("https");
mockRequest.setServerPort(443);
OperationRequest request = this.factory.createOperationRequest(mockRequest);
assertThat(request.getUri(), is(URI.create("https://localhost/foo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
}
@Test
public void httpsRequestWithCustomPort() throws Exception {
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
.buildRequest(new MockServletContext());
mockRequest.setScheme("https");
mockRequest.setServerPort(8443);
OperationRequest request = this.factory.createOperationRequest(mockRequest);
assertThat(request.getUri(), is(URI.create("https://localhost:8443/foo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
}
@Test
public void getRequestWithParametersProducesUriWithQueryString() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.get("/foo").param("a", "alpha", "apple").param("b", "br&vo"));
assertThat(request.getUri(),
is(URI.create("http://localhost/foo?a=alpha&a=apple&b=br%26vo")));
assertThat(request.getParameters().size(), is(2));
assertThat(request.getParameters(),
hasEntry("a", Arrays.asList("alpha", "apple")));
assertThat(request.getParameters(), hasEntry("b", Arrays.asList("br&vo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
}
@Test
public void getRequestWithQueryStringPopulatesParameters() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.get("/foo?a=alpha&b=bravo"));
assertThat(request.getUri(),
is(URI.create("http://localhost/foo?a=alpha&b=bravo")));
assertThat(request.getParameters().size(), is(2));
assertThat(request.getParameters(), hasEntry("a", Arrays.asList("alpha")));
assertThat(request.getParameters(), hasEntry("b", Arrays.asList("bravo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
}
@Test
public void postRequestWithParameters() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.post("/foo").param("a", "alpha", "apple").param("b", "br&vo"));
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
assertThat(request.getMethod(), is(HttpMethod.POST));
assertThat(request.getParameters().size(), is(2));
assertThat(request.getParameters(),
hasEntry("a", Arrays.asList("alpha", "apple")));
assertThat(request.getParameters(), hasEntry("b", Arrays.asList("br&vo")));
}
@Test
public void mockMultipartFileUpload() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.fileUpload("/foo").file(
new MockMultipartFile("file", new byte[] { 1, 2, 3, 4 })));
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
assertThat(request.getMethod(), is(HttpMethod.POST));
assertThat(request.getParts().size(), is(1));
OperationRequestPart part = request.getParts().iterator().next();
assertThat(part.getName(), is(equalTo("file")));
assertThat(part.getSubmittedFileName(), is(nullValue()));
assertThat(part.getHeaders().isEmpty(), is(true));
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
}
@Test
public void mockMultipartFileUploadWithContentType() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.fileUpload("/foo").file(
new MockMultipartFile("file", "original", "image/png",
new byte[] { 1, 2, 3, 4 })));
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
assertThat(request.getMethod(), is(HttpMethod.POST));
assertThat(request.getParts().size(), is(1));
OperationRequestPart part = request.getParts().iterator().next();
assertThat(part.getName(), is(equalTo("file")));
assertThat(part.getSubmittedFileName(), is(equalTo("original")));
assertThat(part.getHeaders().getContentType(), is(MediaType.IMAGE_PNG));
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
}
@Test
public void requestWithPart() throws Exception {
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
.buildRequest(new MockServletContext());
Part mockPart = mock(Part.class);
when(mockPart.getHeaderNames()).thenReturn(Arrays.asList("a", "b"));
when(mockPart.getHeaders("a")).thenReturn(Arrays.asList("alpha"));
when(mockPart.getHeaders("b")).thenReturn(Arrays.asList("bravo", "banana"));
when(mockPart.getInputStream()).thenReturn(
new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }));
when(mockPart.getName()).thenReturn("part-name");
when(mockPart.getSubmittedFileName()).thenReturn("submitted.txt");
mockRequest.addPart(mockPart);
OperationRequest request = this.factory.createOperationRequest(mockRequest);
assertThat(request.getParts().size(), is(1));
OperationRequestPart part = request.getParts().iterator().next();
assertThat(part.getName(), is(equalTo("part-name")));
assertThat(part.getSubmittedFileName(), is(equalTo("submitted.txt")));
assertThat(part.getHeaders().getContentType(), is(nullValue()));
assertThat(part.getHeaders().get("a"), contains("alpha"));
assertThat(part.getHeaders().get("b"), contains("bravo", "banana"));
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
}
@Test
public void requestWithPartWithContentType() throws Exception {
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
.buildRequest(new MockServletContext());
Part mockPart = mock(Part.class);
when(mockPart.getHeaderNames()).thenReturn(Arrays.asList("a", "b"));
when(mockPart.getHeaders("a")).thenReturn(Arrays.asList("alpha"));
when(mockPart.getHeaders("b")).thenReturn(Arrays.asList("bravo", "banana"));
when(mockPart.getInputStream()).thenReturn(
new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }));
when(mockPart.getName()).thenReturn("part-name");
when(mockPart.getSubmittedFileName()).thenReturn("submitted.png");
when(mockPart.getContentType()).thenReturn("image/png");
mockRequest.addPart(mockPart);
OperationRequest request = this.factory.createOperationRequest(mockRequest);
assertThat(request.getParts().size(), is(1));
OperationRequestPart part = request.getParts().iterator().next();
assertThat(part.getName(), is(equalTo("part-name")));
assertThat(part.getSubmittedFileName(), is(equalTo("submitted.png")));
assertThat(part.getHeaders().getContentType(), is(MediaType.IMAGE_PNG));
assertThat(part.getHeaders().get("a"), contains("alpha"));
assertThat(part.getHeaders().get("b"), contains("bravo", "banana"));
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
}
private OperationRequest createOperationRequest(MockHttpServletRequestBuilder builder)
throws Exception {
return this.factory.createOperationRequest(builder
.buildRequest(new MockServletContext()));
}
}

View File

@@ -0,0 +1,378 @@
/*
* Copyright 2014-2015 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.restdocs.mockmvc;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.springframework.restdocs.curl.CurlDocumentation.curlRequest;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.maskLinks;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.attributes;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.restdocs.test.SnippetMatchers.httpRequest;
import static org.springframework.restdocs.test.SnippetMatchers.httpResponse;
import static org.springframework.restdocs.test.SnippetMatchers.snippet;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.junit.After;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.restdocs.hypermedia.Link;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationIntegrationTests.TestConfiguration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
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.util.FileSystemUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Integration tests for Spring REST Docs
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = TestConfiguration.class)
public class MockMvcRestDocumentationIntegrationTests {
@Rule
public RestDocumentation restDocumentation = new RestDocumentation(
"build/generated-snippets");
@Autowired
private WebApplicationContext context;
@Before
public void deleteSnippets() {
FileSystemUtils.deleteRecursively(new File("build/generated-snippets"));
}
@After
public void clearOutputDirSystemProperty() {
System.clearProperty("org.springframework.restdocs.outputDir");
}
@Test
public void basicSnippetGeneration() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(document("basic"));
assertExpectedSnippetFilesExist(new File("build/generated-snippets/basic"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc");
}
@Test
public void linksSnippet() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("links",
links(linkWithRel("rel").description("The description"))));
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
"links.adoc");
}
@Test
public void pathParametersSnippet() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("{foo}", "/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("links", pathParameters(parameterWithName("foo")
.description("The description"))));
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
"path-parameters.adoc");
}
@Test
public void requestParametersSnippet() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("/").param("foo", "bar").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("links", requestParameters(parameterWithName("foo")
.description("The description"))));
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
"request-parameters.adoc");
}
@Test
public void requestFieldsSnippet() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(
get("/").param("foo", "bar").content("{\"a\":\"alpha\"}")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("links",
requestFields(fieldWithPath("a").description("The description"))));
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
"request-fields.adoc");
}
@Test
public void responseFieldsSnippet() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("/").param("foo", "bar").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document(
"links",
responseFields(
fieldWithPath("a").description("The description"),
fieldWithPath("links").description(
"Links to other resources"))));
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
"response-fields.adoc");
}
@Test
public void parameterizedOutputDirectory() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(document("{method-name}"));
assertExpectedSnippetFilesExist(new File(
"build/generated-snippets/parameterized-output-directory"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc");
}
@Test
public void multiStep() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation))
.alwaysDo(document("{method-name}-{step}")).build();
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
status().isOk());
assertExpectedSnippetFilesExist(
new File("build/generated-snippets/multi-step-1/"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
status().isOk());
assertExpectedSnippetFilesExist(
new File("build/generated-snippets/multi-step-2/"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
status().isOk());
assertExpectedSnippetFilesExist(
new File("build/generated-snippets/multi-step-3/"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
}
@Test
public void preprocessedRequest() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
Pattern pattern = Pattern.compile("(\"alpha\")");
mockMvc.perform(
get("/").header("a", "alpha").header("b", "bravo")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON).content("{\"a\":\"alpha\"}"))
.andExpect(status().isOk())
.andDo(document("original-request"))
.andDo(document(
"preprocessed-request",
preprocessRequest(prettyPrint(), removeHeaders("a"),
replacePattern(pattern, "\"<<beta>>\""))));
assertThat(
new File("build/generated-snippets/original-request/http-request.adoc"),
is(snippet().withContents(
httpRequest(RequestMethod.GET, "/").header("Host", "localhost")
.header("a", "alpha").header("b", "bravo")
.header("Content-Type", "application/json")
.header("Accept", MediaType.APPLICATION_JSON_VALUE)
.header("Content-Length", "13")
.content("{\"a\":\"alpha\"}"))));
assertThat(
new File(
"build/generated-snippets/preprocessed-request/http-request.adoc"),
is(snippet().withContents(
httpRequest(RequestMethod.GET, "/").header("Host", "localhost")
.header("b", "bravo")
.header("Content-Type", "application/json")
.header("Accept", MediaType.APPLICATION_JSON_VALUE)
.header("Content-Length", "22")
.content(String.format("{%n \"a\" : \"<<beta>>\"%n}")))));
}
@Test
public void preprocessedResponse() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
Pattern pattern = Pattern.compile("(\"alpha\")");
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("original-response"))
.andDo(document(
"preprocessed-response",
preprocessResponse(prettyPrint(), maskLinks(),
removeHeaders("a"),
replacePattern(pattern, "\"<<beta>>\""))));
assertThat(
new File("build/generated-snippets/original-response/http-response.adoc"),
is(snippet().withContents(
httpResponse(HttpStatus.OK)
.header("a", "alpha")
.header("Content-Type", "application/json")
.content(
"{\"a\":\"alpha\",\"links\":[{\"rel\":\"rel\","
+ "\"href\":\"href\"}]}"))));
assertThat(
new File(
"build/generated-snippets/preprocessed-response/http-response.adoc"),
is(snippet().withContents(
httpResponse(HttpStatus.OK).header("Content-Type",
"application/json").content(
String.format("{%n \"a\" : \"<<beta>>\",%n \"links\" :"
+ " [ {%n \"rel\" : \"rel\",%n \"href\" :"
+ " \"...\"%n } ]%n}")))));
}
@Test
public void customSnippetTemplate() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
ClassLoader classLoader = new URLClassLoader(new URL[] { new File(
"src/test/resources/custom-snippet-templates").toURI().toURL() },
getClass().getClassLoader());
ClassLoader previous = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("custom-snippet-template"));
}
finally {
Thread.currentThread().setContextClassLoader(previous);
}
assertThat(new File(
"build/generated-snippets/custom-snippet-template/curl-request.adoc"),
is(snippet().withContents(equalTo("Custom curl request"))));
mockMvc.perform(get("/")).andDo(
document(
"index",
curlRequest(attributes(key("title").value(
"Access the index using curl")))));
}
private void assertExpectedSnippetFilesExist(File directory, String... snippets) {
for (String snippet : snippets) {
assertTrue(new File(directory, snippet).isFile());
}
}
@Configuration
@EnableWebMvc
static class TestConfiguration extends WebMvcConfigurerAdapter {
@Bean
public TestController testController() {
return new TestController();
}
}
@RestController
static class TestController {
@RequestMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, Object>> foo() {
Map<String, Object> response = new HashMap<>();
response.put("a", "alpha");
response.put("links", Arrays.asList(new Link("rel", "href")));
HttpHeaders headers = new HttpHeaders();
headers.add("a", "alpha");
return new ResponseEntity<Map<String, Object>>(response, headers,
HttpStatus.OK);
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2014-2015 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.restdocs.mockmvc;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.net.URI;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.hateoas.mvc.BasicLinkBuilder;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* Tests for {@link RestDocumentationMockMvcConfigurer}.
*
* @author Andy Wilkinson
* @author Dmitriy Mayboroda
*/
public class RestDocumentationConfigurerTests {
private MockHttpServletRequest request = new MockHttpServletRequest();
@Rule
public RestDocumentation restDocumentation = new RestDocumentation("test");
@Test
public void defaultConfiguration() {
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
this.restDocumentation).beforeMockMvcCreated(null, null);
postProcessor.postProcessRequest(this.request);
assertUriConfiguration("http", "localhost", 8080);
}
@Test
public void customScheme() {
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
this.restDocumentation).uris().withScheme("https")
.beforeMockMvcCreated(null, null);
postProcessor.postProcessRequest(this.request);
assertUriConfiguration("https", "localhost", 8080);
}
@Test
public void customHost() {
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
this.restDocumentation).uris().withHost("api.example.com")
.beforeMockMvcCreated(null, null);
postProcessor.postProcessRequest(this.request);
assertUriConfiguration("http", "api.example.com", 8080);
}
@Test
public void customPort() {
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
this.restDocumentation).uris().withPort(8081)
.beforeMockMvcCreated(null, null);
postProcessor.postProcessRequest(this.request);
assertUriConfiguration("http", "localhost", 8081);
}
@Test
public void noContentLengthHeaderWhenRequestHasNotContent() {
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
this.restDocumentation).uris().withPort(8081)
.beforeMockMvcCreated(null, null);
postProcessor.postProcessRequest(this.request);
assertThat(this.request.getHeader("Content-Length"), is(nullValue()));
}
@Test
public void contentLengthHeaderIsSetWhenRequestHasContent() {
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
this.restDocumentation).beforeMockMvcCreated(null, null);
byte[] content = "Hello, world".getBytes();
this.request.setContent(content);
postProcessor.postProcessRequest(this.request);
assertThat(this.request.getHeader("Content-Length"),
is(equalTo(Integer.toString(content.length))));
}
private void assertUriConfiguration(String scheme, String host, int port) {
assertEquals(scheme, this.request.getScheme());
assertEquals(host, this.request.getServerName());
assertEquals(port, this.request.getServerPort());
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(
this.request));
try {
URI uri = BasicLinkBuilder.linkToCurrentMapping().toUri();
assertEquals(scheme, uri.getScheme());
assertEquals(host, uri.getHost());
assertEquals(port, uri.getPort());
}
finally {
RequestContextHolder.resetRequestAttributes();
}
}
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright 2014-2015 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.restdocs.mockmvc;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.fileUpload;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.head;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.options;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.request;
import java.net.URI;
import javax.servlet.ServletContext;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
/**
* Tests for {@link RestDocumentationRequestBuilders}
*
* @author Andy Wilkinson
*
*/
public class RestDocumentationRequestBuildersTests {
private final ServletContext servletContext = new MockServletContext();
@Test
public void getTemplate() {
assertTemplate(get("{template}", "t"), HttpMethod.GET);
}
@Test
public void getUri() {
assertUri(get(URI.create("/uri")), HttpMethod.GET);
}
@Test
public void postTemplate() {
assertTemplate(post("{template}", "t"), HttpMethod.POST);
}
@Test
public void postUri() {
assertUri(post(URI.create("/uri")), HttpMethod.POST);
}
@Test
public void putTemplate() {
assertTemplate(put("{template}", "t"), HttpMethod.PUT);
}
@Test
public void putUri() {
assertUri(put(URI.create("/uri")), HttpMethod.PUT);
}
@Test
public void patchTemplate() {
assertTemplate(patch("{template}", "t"), HttpMethod.PATCH);
}
@Test
public void patchUri() {
assertUri(patch(URI.create("/uri")), HttpMethod.PATCH);
}
@Test
public void deleteTemplate() {
assertTemplate(delete("{template}", "t"), HttpMethod.DELETE);
}
@Test
public void deleteUri() {
assertUri(delete(URI.create("/uri")), HttpMethod.DELETE);
}
@Test
public void optionsTemplate() {
assertTemplate(options("{template}", "t"), HttpMethod.OPTIONS);
}
@Test
public void optionsUri() {
assertUri(options(URI.create("/uri")), HttpMethod.OPTIONS);
}
@Test
public void headTemplate() {
assertTemplate(head("{template}", "t"), HttpMethod.HEAD);
}
@Test
public void headUri() {
assertUri(head(URI.create("/uri")), HttpMethod.HEAD);
}
@Test
public void requestTemplate() {
assertTemplate(request(HttpMethod.GET, "{template}", "t"), HttpMethod.GET);
}
@Test
public void requestUri() {
assertUri(request(HttpMethod.GET, URI.create("/uri")), HttpMethod.GET);
}
@Test
public void fileUploadTemplate() {
assertTemplate(fileUpload("{template}", "t"), HttpMethod.POST);
}
@Test
public void fileUploadUri() {
assertUri(fileUpload(URI.create("/uri")), HttpMethod.POST);
}
private void assertTemplate(MockHttpServletRequestBuilder builder,
HttpMethod httpMethod) {
MockHttpServletRequest request = builder.buildRequest(this.servletContext);
assertThat(
(String) request.getAttribute("org.springframework.restdocs.urlTemplate"),
is(equalTo("{template}")));
assertThat(request.getRequestURI(), is(equalTo("t")));
assertThat(request.getMethod(), is(equalTo(httpMethod.name())));
}
private void assertUri(MockHttpServletRequestBuilder builder, HttpMethod httpMethod) {
MockHttpServletRequest request = builder.buildRequest(this.servletContext);
assertThat(request.getRequestURI(), is(equalTo("/uri")));
assertThat(request.getMethod(), is(equalTo(httpMethod.name())));
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright 2014-2015 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.restdocs.mockmvc.test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.restdocs.RestDocumentationContext;
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver;
import org.springframework.restdocs.snippet.StandardWriterResolver;
import org.springframework.restdocs.snippet.WriterResolver;
import org.springframework.restdocs.templates.StandardTemplateResourceResolver;
import org.springframework.restdocs.templates.TemplateEngine;
import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* A minimal stub implementation of {@link MvcResult}
*
* @author Andy Wilkinson
*
*/
public class StubMvcResult implements MvcResult {
private final MockHttpServletRequest request;
private final MockHttpServletResponse response;
public static StubMvcResult result() {
return new StubMvcResult();
}
public static StubMvcResult result(RequestBuilder requestBuilder) {
return new StubMvcResult(requestBuilder);
}
public static StubMvcResult result(RequestBuilder requestBuilder,
MockHttpServletResponse response) {
return new StubMvcResult(requestBuilder, response);
}
public static StubMvcResult result(MockHttpServletRequest request) {
return new StubMvcResult(request);
}
public static StubMvcResult result(MockHttpServletResponse response) {
return new StubMvcResult(response);
}
public static StubMvcResult result(MockHttpServletRequest request,
MockHttpServletResponse response) {
return new StubMvcResult(request, response);
}
private StubMvcResult() {
this(new MockHttpServletRequest(), new MockHttpServletResponse());
}
private StubMvcResult(MockHttpServletRequest request) {
this(request, new MockHttpServletResponse());
}
private StubMvcResult(MockHttpServletResponse response) {
this(new MockHttpServletRequest(), response);
}
private StubMvcResult(RequestBuilder requestBuilder, MockHttpServletResponse response) {
this(requestBuilder.buildRequest(new MockServletContext()), response);
}
private StubMvcResult(MockHttpServletRequest request, MockHttpServletResponse response) {
this.request = request;
if (this.request.getAttribute(TemplateEngine.class.getName()) == null) {
this.request.setAttribute(TemplateEngine.class.getName(),
new MustacheTemplateEngine(new StandardTemplateResourceResolver()));
}
RestDocumentationContext context = new RestDocumentationContext(null, null, null);
this.request.setAttribute(RestDocumentationContext.class.getName(), context);
if (this.request.getAttribute(WriterResolver.class.getName()) == null) {
this.request.setAttribute(WriterResolver.class.getName(),
new StandardWriterResolver(
new RestDocumentationContextPlaceholderResolver(context)));
}
this.response = response;
}
private StubMvcResult(RequestBuilder requestBuilder) {
this(requestBuilder.buildRequest(new MockServletContext()));
}
@Override
public MockHttpServletRequest getRequest() {
return this.request;
}
@Override
public MockHttpServletResponse getResponse() {
return this.response;
}
@Override
public Object getHandler() {
return null;
}
@Override
public HandlerInterceptor[] getInterceptors() {
return null;
}
@Override
public ModelAndView getModelAndView() {
return null;
}
@Override
public Exception getResolvedException() {
return null;
}
@Override
public FlashMap getFlashMap() {
return null;
}
@Override
public Object getAsyncResult() {
return null;
}
@Override
public Object getAsyncResult(long timeToWait) {
return null;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2014-2015 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.restdocs.mockmvc.test;
import org.springframework.restdocs.RestDocumentationContext;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
public class TestRequestBuilders {
private TestRequestBuilders() {
}
public static MockHttpServletRequestBuilder get(String urlTemplate,
Object... urlVariables) {
return org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get(
urlTemplate, urlVariables).requestAttr(
RestDocumentationContext.class.getName(),
new RestDocumentationContext(null, null, null));
}
}