Reduce duplication by introducing RestDocumentationHandler
Previously, logic for creating an Operation, determining the snippets to call, and calling them was duplicated in both the MockMvc and REST Assured modules. This commit introduces a new core class, RestDocumentationHandler, that now does the bulk of the work in a reusable manner. The MockMvc and REST Assured modules have been updated to delegate to RestDocumentationHandler. Closes gh-194
This commit is contained in:
@@ -30,20 +30,23 @@ import org.springframework.restdocs.operation.OperationRequestFactory;
|
||||
import org.springframework.restdocs.operation.OperationRequestPart;
|
||||
import org.springframework.restdocs.operation.OperationRequestPartFactory;
|
||||
import org.springframework.restdocs.operation.Parameters;
|
||||
import org.springframework.restdocs.operation.RequestConverter;
|
||||
|
||||
import com.jayway.restassured.response.Header;
|
||||
import com.jayway.restassured.specification.FilterableRequestSpecification;
|
||||
import com.jayway.restassured.specification.MultiPartSpecification;
|
||||
|
||||
/**
|
||||
* A factory for creating an {@link OperationRequest} derived from a REST Assured
|
||||
* A converter for creating an {@link OperationRequest} from a REST Assured
|
||||
* {@link FilterableRequestSpecification}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class RestAssuredOperationRequestFactory {
|
||||
class RestAssuredRequestConverter implements
|
||||
RequestConverter<FilterableRequestSpecification> {
|
||||
|
||||
OperationRequest createOperationRequest(FilterableRequestSpecification requestSpec) {
|
||||
@Override
|
||||
public OperationRequest convert(FilterableRequestSpecification requestSpec) {
|
||||
return new OperationRequestFactory().create(URI.create(requestSpec.getURI()),
|
||||
HttpMethod.valueOf(requestSpec.getMethod().name()),
|
||||
extractContent(requestSpec), extractHeaders(requestSpec),
|
||||
@@ -20,19 +20,21 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.restdocs.operation.OperationResponse;
|
||||
import org.springframework.restdocs.operation.OperationResponseFactory;
|
||||
import org.springframework.restdocs.operation.ResponseConverter;
|
||||
|
||||
import com.jayway.restassured.response.Header;
|
||||
import com.jayway.restassured.response.Response;
|
||||
|
||||
/**
|
||||
* A factory for creating an {@link OperationResponse} derived from a REST Assured
|
||||
* A converter for creating an {@link OperationResponse} from a REST Assured
|
||||
* {@link Response}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class RestAssuredOperationResponseFactory {
|
||||
class RestAssuredResponseConverter implements ResponseConverter<Response> {
|
||||
|
||||
OperationResponse createOperationResponse(Response response) {
|
||||
@Override
|
||||
public OperationResponse convert(Response response) {
|
||||
return new OperationResponseFactory().create(
|
||||
HttpStatus.valueOf(response.getStatusCode()), extractHeaders(response),
|
||||
extractContent(response));
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.restdocs.restassured;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentation;
|
||||
import org.springframework.restdocs.RestDocumentationHandler;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
|
||||
import org.springframework.restdocs.snippet.Snippet;
|
||||
@@ -28,6 +29,10 @@ import org.springframework.restdocs.snippet.Snippet;
|
||||
*/
|
||||
public abstract class RestAssuredRestDocumentation {
|
||||
|
||||
private static final RestAssuredRequestConverter REQUEST_CONVERTER = new RestAssuredRequestConverter();
|
||||
|
||||
private static final RestAssuredResponseConverter RESPONSE_CONVERTER = new RestAssuredResponseConverter();
|
||||
|
||||
private RestAssuredRestDocumentation() {
|
||||
|
||||
}
|
||||
@@ -41,7 +46,8 @@ public abstract class RestAssuredRestDocumentation {
|
||||
* @return a {@link RestDocumentationFilter} that will produce the documentation
|
||||
*/
|
||||
public static RestDocumentationFilter document(String identifier, Snippet... snippets) {
|
||||
return new RestDocumentationFilter(identifier, snippets);
|
||||
return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier,
|
||||
REQUEST_CONVERTER, RESPONSE_CONVERTER, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +62,8 @@ public abstract class RestAssuredRestDocumentation {
|
||||
*/
|
||||
public static RestDocumentationFilter document(String identifier,
|
||||
OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationFilter(identifier, requestPreprocessor, snippets);
|
||||
return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier,
|
||||
REQUEST_CONVERTER, RESPONSE_CONVERTER, requestPreprocessor, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +78,8 @@ public abstract class RestAssuredRestDocumentation {
|
||||
*/
|
||||
public static RestDocumentationFilter document(String identifier,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationFilter(identifier, responsePreprocessor, snippets);
|
||||
return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier,
|
||||
REQUEST_CONVERTER, RESPONSE_CONVERTER, responsePreprocessor, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,8 +97,9 @@ public abstract class RestAssuredRestDocumentation {
|
||||
public static RestDocumentationFilter document(String identifier,
|
||||
OperationRequestPreprocessor requestPreprocessor,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationFilter(identifier, requestPreprocessor,
|
||||
responsePreprocessor, snippets);
|
||||
return new RestDocumentationFilter(new RestDocumentationHandler<>(identifier,
|
||||
REQUEST_CONVERTER, RESPONSE_CONVERTER, requestPreprocessor,
|
||||
responsePreprocessor, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,22 +16,13 @@
|
||||
|
||||
package org.springframework.restdocs.restassured;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationContext;
|
||||
import org.springframework.restdocs.config.SnippetConfigurer;
|
||||
import org.springframework.restdocs.operation.Operation;
|
||||
import org.springframework.restdocs.operation.OperationRequest;
|
||||
import org.springframework.restdocs.operation.OperationResponse;
|
||||
import org.springframework.restdocs.operation.StandardOperation;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
|
||||
import org.springframework.restdocs.RestDocumentationHandler;
|
||||
import org.springframework.restdocs.snippet.Snippet;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.jayway.restassured.filter.Filter;
|
||||
import com.jayway.restassured.filter.FilterContext;
|
||||
@@ -46,40 +37,12 @@ import com.jayway.restassured.specification.FilterableResponseSpecification;
|
||||
*/
|
||||
public final class RestDocumentationFilter implements Filter {
|
||||
|
||||
private final String identifier;
|
||||
private final RestDocumentationHandler<FilterableRequestSpecification, Response> delegate;
|
||||
|
||||
private final OperationRequestPreprocessor requestPreprocessor;
|
||||
|
||||
private final OperationResponsePreprocessor responsePreprocessor;
|
||||
|
||||
private final List<Snippet> snippets;
|
||||
|
||||
RestDocumentationFilter(String identifier, Snippet... snippets) {
|
||||
this(identifier, new IdentityOperationRequestPreprocessor(),
|
||||
new IdentityOperationResponsePreprocessor(), snippets);
|
||||
}
|
||||
|
||||
RestDocumentationFilter(String identifier,
|
||||
OperationRequestPreprocessor operationRequestPreprocessor,
|
||||
Snippet... snippets) {
|
||||
this(identifier, operationRequestPreprocessor,
|
||||
new IdentityOperationResponsePreprocessor(), snippets);
|
||||
}
|
||||
|
||||
RestDocumentationFilter(String identifier,
|
||||
OperationResponsePreprocessor operationResponsePreprocessor,
|
||||
Snippet... snippets) {
|
||||
this(identifier, new IdentityOperationRequestPreprocessor(),
|
||||
operationResponsePreprocessor, snippets);
|
||||
}
|
||||
|
||||
RestDocumentationFilter(String identifier,
|
||||
OperationRequestPreprocessor requestPreprocessor,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
this.identifier = identifier;
|
||||
this.requestPreprocessor = requestPreprocessor;
|
||||
this.responsePreprocessor = responsePreprocessor;
|
||||
this.snippets = new ArrayList<>(Arrays.asList(snippets));
|
||||
RestDocumentationFilter(
|
||||
RestDocumentationHandler<FilterableRequestSpecification, Response> delegate) {
|
||||
Assert.notNull(delegate, "delegate must be non-null");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,35 +50,15 @@ public final class RestDocumentationFilter implements Filter {
|
||||
FilterableResponseSpecification responseSpec, FilterContext context) {
|
||||
Response response = context.next(requestSpec, responseSpec);
|
||||
|
||||
OperationRequest operationRequest = this.requestPreprocessor
|
||||
.preprocess(new RestAssuredOperationRequestFactory()
|
||||
.createOperationRequest(requestSpec));
|
||||
OperationResponse operationResponse = this.responsePreprocessor
|
||||
.preprocess(new RestAssuredOperationResponseFactory()
|
||||
.createOperationResponse(response));
|
||||
|
||||
RestDocumentationContext documentationContext = context
|
||||
.getValue(RestDocumentationContext.class.getName());
|
||||
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put(RestDocumentationContext.class.getName(), documentationContext);
|
||||
attributes.put("org.springframework.restdocs.urlTemplate",
|
||||
Map<String, Object> configuration = new HashMap<>(
|
||||
context.<Map<String, Object>>getValue("org.springframework.restdocs.configuration"));
|
||||
configuration.put(RestDocumentationContext.class.getName(), context
|
||||
.<RestDocumentationContext>getValue(RestDocumentationContext.class
|
||||
.getName()));
|
||||
configuration.put("org.springframework.restdocs.urlTemplate",
|
||||
requestSpec.getUserDefinedPath());
|
||||
Map<String, Object> configuration = context
|
||||
.getValue("org.springframework.restdocs.configuration");
|
||||
attributes.putAll(configuration);
|
||||
|
||||
Operation operation = new StandardOperation(this.identifier, operationRequest,
|
||||
operationResponse, attributes);
|
||||
|
||||
try {
|
||||
for (Snippet snippet : getSnippets(configuration)) {
|
||||
snippet.document(operation);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
this.delegate.handle(requestSpec, response, configuration);
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -128,37 +71,8 @@ public final class RestDocumentationFilter implements Filter {
|
||||
* @return this {@code RestDocumentationFilter}
|
||||
*/
|
||||
public RestDocumentationFilter snippets(Snippet... snippets) {
|
||||
this.snippets.addAll(Arrays.asList(snippets));
|
||||
this.delegate.addSnippets(snippets);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Snippet> getSnippets(Map<String, Object> configuration) {
|
||||
List<Snippet> combinedSnippets = new ArrayList<>(
|
||||
(List<Snippet>) configuration
|
||||
.get(SnippetConfigurer.ATTRIBUTE_DEFAULT_SNIPPETS));
|
||||
combinedSnippets.addAll(this.snippets);
|
||||
return combinedSnippets;
|
||||
}
|
||||
|
||||
private static final class IdentityOperationRequestPreprocessor implements
|
||||
OperationRequestPreprocessor {
|
||||
|
||||
@Override
|
||||
public OperationRequest preprocess(OperationRequest request) {
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class IdentityOperationResponsePreprocessor implements
|
||||
OperationResponsePreprocessor {
|
||||
|
||||
@Override
|
||||
public OperationResponse preprocess(OperationResponse response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.restdocs.operation.OperationRequest;
|
||||
import org.springframework.restdocs.operation.OperationRequestPart;
|
||||
import org.springframework.restdocs.restassured.RestAssuredOperationRequestFactoryTests.TestApplication;
|
||||
import org.springframework.restdocs.restassured.RestAssuredRequestConverterTests.TestApplication;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -51,7 +51,7 @@ import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestAssuredOperationRequestFactory}.
|
||||
* Tests for {@link RestAssuredRequestConverter}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@@ -59,12 +59,12 @@ import static org.junit.Assert.assertThat;
|
||||
@SpringApplicationConfiguration(classes = TestApplication.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest("server.port=0")
|
||||
public class RestAssuredOperationRequestFactoryTests {
|
||||
public class RestAssuredRequestConverterTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final RestAssuredOperationRequestFactory factory = new RestAssuredOperationRequestFactory();
|
||||
private final RestAssuredRequestConverter factory = new RestAssuredRequestConverter();
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port;
|
||||
@@ -74,7 +74,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(this.port);
|
||||
requestSpec.get("/foo/bar");
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getUri(),
|
||||
is(equalTo(URI.create("http://localhost:" + this.port + "/foo/bar"))));
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(this.port);
|
||||
requestSpec.head("/foo/bar");
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getMethod(), is(equalTo(HttpMethod.HEAD)));
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.queryParam("foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters().size(), is(1));
|
||||
assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar"))));
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(this.port);
|
||||
requestSpec.get("/?foo=bar");
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters().size(), is(1));
|
||||
assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar"))));
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.formParameter("foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters().size(), is(1));
|
||||
assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar"))));
|
||||
}
|
||||
@@ -126,7 +126,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.parameter("foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters().size(), is(1));
|
||||
assertThat(request.getParameters().get("foo"), is(equalTo(Arrays.asList("bar"))));
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.header("Foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getHeaders().toString(), request.getHeaders().size(), is(3));
|
||||
assertThat(request.getHeaders().get("Foo"), is(equalTo(Arrays.asList("bar"))));
|
||||
assertThat(request.getHeaders().get("Accept"), is(equalTo(Arrays.asList("*/*"))));
|
||||
@@ -152,7 +152,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.multiPart("b", new ObjectBody("bar"), "application/json");
|
||||
requestSpec.post().then().statusCode(200);
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
Collection<OperationRequestPart> parts = request.getParts();
|
||||
assertThat(parts.size(), is(2));
|
||||
Iterator<OperationRequestPart> iterator = parts.iterator();
|
||||
@@ -174,7 +174,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
RequestSpecification requestSpec = RestAssured.given().body("body".getBytes())
|
||||
.port(this.port);
|
||||
requestSpec.post();
|
||||
this.factory.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -183,7 +183,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.port(this.port);
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getContentAsString(), is(equalTo("body")));
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.body(new ObjectBody("bar")).port(this.port);
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory
|
||||
.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getContentAsString(), is(equalTo("{\"foo\":\"bar\"}")));
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
requestSpec.post();
|
||||
this.thrown
|
||||
.expectMessage(equalTo("Unsupported request content: java.io.ByteArrayInputStream"));
|
||||
this.factory.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -214,7 +214,7 @@ public class RestAssuredOperationRequestFactoryTests {
|
||||
.body(new File("src/test/resources/body.txt")).port(this.port);
|
||||
requestSpec.post();
|
||||
this.thrown.expectMessage(equalTo("Unsupported request content: java.io.File"));
|
||||
this.factory.createOperationRequest((FilterableRequestSpecification) requestSpec);
|
||||
this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
Reference in New Issue
Block a user