Restore support for REST Assured
Closes gh-784
This commit is contained in:
@@ -117,6 +117,7 @@ subprojects { subproject ->
|
||||
samples {
|
||||
dependOn "spring-restdocs-core:publishToMavenLocal"
|
||||
dependOn "spring-restdocs-mockmvc:publishToMavenLocal"
|
||||
dependOn "spring-restdocs-restassured:publishToMavenLocal"
|
||||
dependOn "spring-restdocs-webtestclient:publishToMavenLocal"
|
||||
dependOn "spring-restdocs-asciidoctor:publishToMavenLocal"
|
||||
|
||||
@@ -132,6 +133,10 @@ samples {
|
||||
workingDir "$projectDir/samples/testng"
|
||||
}
|
||||
|
||||
restAssured {
|
||||
workingDir "$projectDir/samples/rest-assured"
|
||||
}
|
||||
|
||||
webTestClient {
|
||||
workingDir "$projectDir/samples/web-test-client"
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ dependencies {
|
||||
internal(enforcedPlatform("org.springframework:spring-framework-bom:$springFrameworkVersion"))
|
||||
|
||||
testImplementation(project(":spring-restdocs-mockmvc"))
|
||||
testImplementation(project(":spring-restdocs-restassured"))
|
||||
testImplementation(project(":spring-restdocs-webtestclient"))
|
||||
testImplementation("jakarta.validation:jakarta.validation-api")
|
||||
testImplementation("junit:junit")
|
||||
|
||||
@@ -45,6 +45,17 @@ TIP: To configure a request's context path, use the `contextPath` method on `Moc
|
||||
|
||||
|
||||
|
||||
[[configuration-uris-rest-assured]]
|
||||
==== REST Assured URI Customization
|
||||
|
||||
REST Assured tests a service by making actual HTTP requests. As a result, URIs must be
|
||||
customized once the operation on the service has been performed but before it is
|
||||
documented. A
|
||||
<<customizing-requests-and-responses-preprocessors-modify-uris, REST-Assured-specific
|
||||
preprocessor>> is provided for this purpose.
|
||||
|
||||
|
||||
|
||||
[[configuration-uris-webtestclient]]
|
||||
==== WebTestClient URI Customization
|
||||
|
||||
@@ -79,6 +90,12 @@ include::{examples-dir}/com/example/mockmvc/CustomEncoding.java[tags=custom-enco
|
||||
include::{examples-dir}/com/example/webtestclient/CustomEncoding.java[tags=custom-encoding]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/CustomEncoding.java[tags=custom-encoding]
|
||||
----
|
||||
|
||||
TIP: When Spring REST Docs converts the content of a request or a response to a `String`, the `charset` specified in the `Content-Type` header is used if it is available.
|
||||
In its absence, the JVM's default `Charset` is used.
|
||||
You can configure the JVM's default `Charset` by using the `file.encoding` system property.
|
||||
@@ -105,6 +122,13 @@ include::{examples-dir}/com/example/mockmvc/CustomFormat.java[tags=custom-format
|
||||
include::{examples-dir}/com/example/webtestclient/CustomFormat.java[tags=custom-format]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/CustomFormat.java[tags=custom-format]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[configuration-default-snippets]]
|
||||
@@ -134,6 +158,12 @@ include::{examples-dir}/com/example/mockmvc/CustomDefaultSnippets.java[tags=cust
|
||||
include::{examples-dir}/com/example/webtestclient/CustomDefaultSnippets.java[tags=custom-default-snippets]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/CustomDefaultSnippets.java[tags=custom-default-snippets]
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[configuration-default-preprocessors]]
|
||||
@@ -158,4 +188,10 @@ include::{examples-dir}/com/example/webtestclient/CustomDefaultOperationPreproce
|
||||
<1> Apply a request preprocessor that removes the header named `Foo`.
|
||||
<2> Apply a response preprocessor that pretty prints its content.
|
||||
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/CustomDefaultOperationPreprocessors.java[tags=custom-default-operation-preprocessors]
|
||||
----
|
||||
<1> Apply a request preprocessor that removes the header named `Foo`.
|
||||
<2> Apply a response preprocessor that pretty prints its content.
|
||||
|
||||
@@ -24,6 +24,14 @@ include::{examples-dir}/com/example/webtestclient/PerTestPreprocessing.java[tags
|
||||
<1> Apply a request preprocessor that removes the header named `Foo`.
|
||||
<2> Apply a response preprocessor that pretty prints its content.
|
||||
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/PerTestPreprocessing.java[tags=preprocessing]
|
||||
----
|
||||
<1> Apply a request preprocessor that removes the header named `Foo`.
|
||||
<2> Apply a response preprocessor that pretty prints its content.
|
||||
====
|
||||
|
||||
Alternatively, you may want to apply the same preprocessors to every test.
|
||||
You can do so by using the `RestDocumentationConfigurer` API in your `@Before` method to configure the preprocessors.
|
||||
For example, to remove the `Foo` header from all requests and pretty print all responses, you could do one of the following (depending on your testing environment):
|
||||
@@ -44,6 +52,14 @@ include::{examples-dir}/com/example/webtestclient/EveryTestPreprocessing.java[ta
|
||||
<1> Apply a request preprocessor that removes the header named `Foo`.
|
||||
<2> Apply a response preprocessor that pretty prints its content.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/EveryTestPreprocessing.java[tags=setup]
|
||||
----
|
||||
<1> Apply a request preprocessor that removes the header named `Foo`.
|
||||
<2> Apply a response preprocessor that pretty prints its content.
|
||||
|
||||
Then, in each test, you can perform any configuration specific to that test.
|
||||
The following examples show how to do so:
|
||||
|
||||
@@ -59,6 +75,12 @@ include::{examples-dir}/com/example/mockmvc/EveryTestPreprocessing.java[tags=use
|
||||
include::{examples-dir}/com/example/webtestclient/EveryTestPreprocessing.java[tags=use]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/EveryTestPreprocessing.java[tags=use]
|
||||
----
|
||||
|
||||
Various built-in preprocessors, including those illustrated above, are available through the static methods on `Preprocessors`.
|
||||
See <<Preprocessors, below>> for further details.
|
||||
|
||||
@@ -116,7 +138,7 @@ You can use `modifyParameters` on `Preprocessors` to add, set, and remove reques
|
||||
TIP: If you use MockMvc or a WebTestClient that is not bound to a server, you should customize URIs by <<configuration-uris, changing the configuration>>.
|
||||
|
||||
You can use `modifyUris` on `Preprocessors` to modify any URIs in a request or a response.
|
||||
When using WebTestClient bound to a server, this lets you customize the URIs that appear in the documentation while testing a local instance of the service.
|
||||
When using REST Assured or WebTestClient bound to a server, this lets you customize the URIs that appear in the documentation while testing a local instance of the service.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,18 @@ Uses the static `links` method on `org.springframework.restdocs.hypermedia.Hyper
|
||||
Uses the static `linkWithRel` method on `org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
|
||||
<3> Expect a link whose `rel` is `bravo`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Hypermedia.java[tag=links]
|
||||
----
|
||||
<1> Configure Spring REST docs to produce a snippet describing the response's links.
|
||||
Uses the static `links` method on
|
||||
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
|
||||
<2> Expect a link whose `rel` is `alpha`. Uses the static `linkWithRel` method on
|
||||
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
|
||||
<3> Expect a link whose `rel` is `bravo`.
|
||||
|
||||
The result is a snippet named `links.adoc` that contains a table describing the resource's links.
|
||||
|
||||
TIP: If a link in the response has a `title`, you can omit the description from its descriptor and the `title` is used.
|
||||
@@ -79,6 +91,14 @@ include::{examples-dir}/com/example/webtestclient/Hypermedia.java[tag=explicit-e
|
||||
<1> Indicate that the links are in HAL format.
|
||||
Uses the static `halLinks` method on `org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Hypermedia.java[tag=explicit-extractor]
|
||||
----
|
||||
<1> Indicate that the links are in HAL format. Uses the static `halLinks` method on
|
||||
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
|
||||
|
||||
If your API represents its links in a format other than Atom or HAL, you can provide your own implementation of the `LinkExtractor` interface to extract the links from the response.
|
||||
|
||||
|
||||
@@ -150,6 +170,18 @@ Both are static methods on `org.springframework.restdocs.payload.PayloadDocument
|
||||
Uses the static `fieldWithPath` method on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
<3> Expect a field with the path `contact.name`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=response]
|
||||
----
|
||||
<1> Configure Spring REST docs to produce a snippet describing the fields in the response payload.
|
||||
To document a request, you can use `requestFields`.
|
||||
Both are static methods on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
<2> Expect a field with the path `contact.email`.
|
||||
Uses the static `fieldWithPath` method on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
<3> Expect a field with the path `contact.name`.
|
||||
|
||||
The result is a snippet that contains a table describing the fields.
|
||||
For requests, this snippet is named `request-fields.adoc`.
|
||||
For responses, this snippet is named `response-fields.adoc`.
|
||||
@@ -178,6 +210,14 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=subsection]
|
||||
`contact.email` and `contact.name` are now seen as having also been documented.
|
||||
Uses the static `subsectionWithPath` method on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=subsection]
|
||||
----
|
||||
<1> Document the subsection with the path `contact`. `contact.email` and `contact.name` are now seen as having also been documented.
|
||||
Uses the static `subsectionWithPath` method on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
|
||||
`subsectionWithPath` can be useful for providing a high-level overview of a particular section of a payload.
|
||||
You can then produce separate, more detailed documentation for a subsection.
|
||||
See <<documenting-your-api-request-response-payloads-subsections>>.
|
||||
@@ -357,6 +397,13 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=explicit-typ
|
||||
----
|
||||
<1> Set the field's type to `String`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=explicit-type]
|
||||
----
|
||||
<1> Set the field's type to `String`.
|
||||
|
||||
|
||||
|
||||
[[documenting-your-api-request-response-payloads-fields-xml]]
|
||||
@@ -440,6 +487,13 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=single-book]
|
||||
----
|
||||
<1> Document `title` and `author` by using existing descriptors
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=single-book]
|
||||
----
|
||||
<1> Document `title` and `author` by using existing descriptors
|
||||
|
||||
You can also use the descriptors to document an array of books, as follows:
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
@@ -460,6 +514,16 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=book-array]
|
||||
|
||||
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=book-array]
|
||||
----
|
||||
<1> Document the array.
|
||||
<2> Document `[].title` and `[].author` by using the existing descriptors prefixed with `[].`
|
||||
|
||||
|
||||
|
||||
[[documenting-your-api-request-response-payloads-subsections]]
|
||||
==== Documenting a Subsection of a Request or Response Payload
|
||||
|
||||
@@ -509,6 +573,15 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=body-subsect
|
||||
Uses the static `responseBody` and `beneathPath` methods on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
To produce a snippet for the request body, you can use `requestBody` in place of `responseBody`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=body-subsection]
|
||||
----
|
||||
<1> Produce a snippet containing a subsection of the response body.
|
||||
Uses the static `responseBody` and `beneathPath` methods on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
To produce a snippet for the request body, you can use `requestBody` in place of `responseBody`.
|
||||
|
||||
The result is a snippet with the following contents:
|
||||
|
||||
[source,json,indent=0]
|
||||
@@ -559,6 +632,16 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=fields-subse
|
||||
Uses the static `beneathPath` method on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
<2> Document the `high` and `low` fields.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=fields-subsection]
|
||||
----
|
||||
<1> Produce a snippet describing the fields in the subsection of the response payload
|
||||
beneath the path `weather.temperature`. Uses the static `beneathPath` method on
|
||||
`org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
<2> Document the `high` and `low` fields.
|
||||
|
||||
The result is a snippet that contains a table describing the `high` and `low` fields of `weather.temperature`.
|
||||
To make the snippet's name distinct, an identifier for the subsection is included.
|
||||
By default, this identifier is `beneath-${path}`.
|
||||
@@ -597,6 +680,18 @@ Uses the static `requestParameters` method on `org.springframework.restdocs.requ
|
||||
Uses the static `parameterWithName` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<4> Document the `per_page` parameter.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/RequestParameters.java[tags=request-parameters-query-string]
|
||||
----
|
||||
<1> Configure Spring REST Docs to produce a snippet describing the request's parameters.
|
||||
Uses the static `requestParameters` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<2> Document the `page` parameter.
|
||||
Uses the static `parameterWithName` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<3> Document the `per_page` parameter.
|
||||
<4> Perform a `GET` request with two parameters, `page` and `per_page`, in the query string.
|
||||
|
||||
You can also include request parameters as form data in the body of a POST request.
|
||||
The following examples show how to do so:
|
||||
|
||||
@@ -614,6 +709,14 @@ include::{examples-dir}/com/example/webtestclient/RequestParameters.java[tags=re
|
||||
----
|
||||
<1> Perform a `POST` request with a single parameter, `username`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/RequestParameters.java[tags=request-parameters-form-data]
|
||||
----
|
||||
<1> Configure the `username` parameter.
|
||||
<2> Perform the `POST` request.
|
||||
|
||||
In all cases, the result is a snippet named `request-parameters.adoc` that contains a table describing the parameters that are supported by the resource.
|
||||
|
||||
When documenting request parameters, the test fails if an undocumented request parameter is used in the request.
|
||||
@@ -658,6 +761,18 @@ Uses the static `pathParameters` method on `org.springframework.restdocs.request
|
||||
Uses the static `parameterWithName` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<4> Document the parameter named `longitude`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/PathParameters.java[tags=path-parameters]
|
||||
----
|
||||
<1> Configure Spring REST Docs to produce a snippet describing the request's path parameters.
|
||||
Uses the static `pathParameters` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<2> Document the parameter named `latitude`.
|
||||
Uses the static `parameterWithName` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<3> Document the parameter named `longitude`.
|
||||
<4> Perform a `GET` request with two path parameters, `latitude` and `longitude`.
|
||||
|
||||
The result is a snippet named `path-parameters.adoc` that contains a table describing the path parameters that are supported by the resource.
|
||||
|
||||
TIP: If you use MockMvc, to make the path parameters available for documentation, you must build the request by using one of the methods on `RestDocumentationRequestBuilders` rather than `MockMvcRequestBuilders`.
|
||||
@@ -702,6 +817,17 @@ Uses the static `requestParts` method on `org.springframework.restdocs.request.R
|
||||
<3> Document the part named `file`.
|
||||
Uses the static `partWithName` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/RequestParts.java[tags=request-parts]
|
||||
----
|
||||
<1> Configure Spring REST Docs to produce a snippet describing the request's parts.
|
||||
Uses the static `requestParts` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<2> Document the part named `file`. Uses the static `partWithName` method on `org.springframework.restdocs.request.RequestDocumentation`.
|
||||
<3> Configure the request with the part named `file`.
|
||||
<4> Perform the `POST` request to `/upload`.
|
||||
|
||||
The result is a snippet named `request-parts.adoc` that contains a table describing the request parts that are supported by the resource.
|
||||
|
||||
When documenting request parts, the test fails if an undocumented part is used in the request.
|
||||
@@ -744,6 +870,14 @@ include::{examples-dir}/com/example/webtestclient/RequestPartPayload.java[tags=b
|
||||
<1> Configure Spring REST docs to produce a snippet containing the body of the request part named `metadata`.
|
||||
Uses the static `requestPartBody` method on `PayloadDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/RequestPartPayload.java[tags=body]
|
||||
----
|
||||
<1> Configure Spring REST docs to produce a snippet containing the body of the request part named `metadata`.
|
||||
Uses the static `requestPartBody` method on `PayloadDocumentation`.
|
||||
|
||||
The result is a snippet named `request-part-${part-name}-body.adoc` that contains the part's body.
|
||||
For example, documenting a part named `metadata` produces a snippet named `request-part-metadata-body.adoc`.
|
||||
|
||||
@@ -774,6 +908,16 @@ Uses the static `requestPartFields` method on `PayloadDocumentation`.
|
||||
<2> Expect a field with the path `version`.
|
||||
Uses the static `fieldWithPath` method on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/RequestPartPayload.java[tags=fields]
|
||||
----
|
||||
<1> Configure Spring REST docs to produce a snippet describing the fields in the payload of the request part named `metadata`.
|
||||
Uses the static `requestPartFields` method on `PayloadDocumentation`.
|
||||
<2> Expect a field with the path `version`.
|
||||
Uses the static `fieldWithPath` method on `org.springframework.restdocs.payload.PayloadDocumentation`.
|
||||
|
||||
The result is a snippet that contains a table describing the part's fields.
|
||||
This snippet is named `request-part-${part-name}-fields.adoc`.
|
||||
For example, documenting a part named `metadata` produces a snippet named `request-part-metadata-fields.adoc`.
|
||||
@@ -825,6 +969,19 @@ Uses the static `headerWithName` method on `org.springframework.restdocs.headers
|
||||
<4> Produce a snippet describing the response's headers.
|
||||
Uses the static `responseHeaders` method on `org.springframework.restdocs.headers.HeaderDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/HttpHeaders.java[tags=headers]
|
||||
----
|
||||
<1> Configure Spring REST Docs to produce a snippet describing the request's headers.
|
||||
Uses the static `requestHeaders` method on `org.springframework.restdocs.headers.HeaderDocumentation`.
|
||||
<2> Document the `Authorization` header.
|
||||
Uses the static `headerWithName` method on `org.springframework.restdocs.headers.HeaderDocumentation.
|
||||
<3> Produce a snippet describing the response's headers.
|
||||
Uses the static `responseHeaders` method on `org.springframework.restdocs.headers.HeaderDocumentation`.
|
||||
<4> Configure the request with an `Authorization` header that uses basic authentication.
|
||||
|
||||
The result is a snippet named `request-headers.adoc` and a snippet named `response-headers.adoc`.
|
||||
Each contains a table describing the headers.
|
||||
|
||||
@@ -863,6 +1020,13 @@ include::{examples-dir}/com/example/webtestclient/WebTestClientSnippetReuse.java
|
||||
----
|
||||
<1> Reuse the `pagingLinks` `Snippet`, calling `and` to add descriptors that are specific to the resource that is being documented.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/RestAssuredSnippetReuse.java[tags=use]
|
||||
----
|
||||
<1> Reuse the `pagingLinks` `Snippet`, calling `and` to add descriptors that are specific to the resource that is being documented.
|
||||
|
||||
The result of the example is that links with `rel` values of `first`, `last`, `next`, `previous`, `alpha`, and `bravo` are all documented.
|
||||
|
||||
|
||||
@@ -1045,6 +1209,12 @@ The following examples show how to do so:
|
||||
include::{examples-dir}/com/example/mockmvc/ParameterizedOutput.java[tags=parameterized-output]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/ParameterizedOutput.java[tags=parameterized-output]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.WebTestClient
|
||||
----
|
||||
@@ -1112,8 +1282,16 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=constraints]
|
||||
<2> Set the `constraints` attribute for the `name` field.
|
||||
<3> Set the `constraints` attribute for the `email` field.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=constraints]
|
||||
----
|
||||
<1> Configure the `title` attribute for the request fields snippet.
|
||||
<2> Set the `constraints` attribute for the `name` field.
|
||||
<3> Set the `constraints` attribute for the `email` field.
|
||||
|
||||
The second step is to provide a custom template named `request-fields.snippet` that includes the information about the fields' constraints in the generated snippet's table and adds a title.
|
||||
The following example shows how to do so:
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
|
||||
@@ -34,6 +34,19 @@ If you want to jump straight in, a number of sample applications are available:
|
||||
| Demonstrates the use of Spring REST docs with Spring WebFlux's WebTestClient.
|
||||
|===
|
||||
|
||||
|
||||
[cols="3,2,10"]
|
||||
.REST Assured
|
||||
|===
|
||||
| Sample | Build system | Description
|
||||
|
||||
| {samples}/rest-assured[REST Assured]
|
||||
| Gradle
|
||||
| Demonstrates the use of Spring REST Docs with http://rest-assured.io[REST Assured].
|
||||
|
||||
|===
|
||||
|
||||
|
||||
[cols="3,2,10"]
|
||||
.Advanced
|
||||
|===
|
||||
@@ -63,7 +76,7 @@ Spring REST Docs has the following minimum requirements:
|
||||
* Java 17
|
||||
* Spring Framework 6
|
||||
|
||||
|
||||
Additionally, the `spring-restdocs-restassured` module requires REST Assured 4 (4.5 or later).
|
||||
|
||||
[[getting-started-build-configuration]]
|
||||
=== Build configuration
|
||||
@@ -113,7 +126,7 @@ The key parts of the configuration are described in the following listings:
|
||||
</build>
|
||||
----
|
||||
<1> Add a dependency on `spring-restdocs-mockmvc` in the `test` scope.
|
||||
If you want to use `WebTestClient` add a dependency on `spring-restdocs-webtestclient` instead.
|
||||
If you want to use `WebTestClient` or REST Assured rather than MockMvc, add a dependency on `spring-restdocs-webtestclient` or `spring-restdocs-restassured` respectively instead.
|
||||
<2> Add the Asciidoctor plugin.
|
||||
<3> Using `prepare-package` allows the documentation to be <<getting-started-build-configuration-packaging-the-documentation, included in the package>>.
|
||||
<4> Add `spring-restdocs-asciidoctor` as a dependency of the Asciidoctor plugin.
|
||||
@@ -156,7 +169,7 @@ It will also allow you to use the `operation` block macro.
|
||||
This will automatically configure the `snippets` attribute for use in your `.adoc` files to point to `build/generated-snippets`.
|
||||
It will also allow you to use the `operation` block macro.
|
||||
<4> Add a dependency on `spring-restdocs-mockmvc` in the `testImplementation` configuration.
|
||||
If you want to use `WebTestClient`, add a dependency on `spring-restdocs-webtestclient` instead.
|
||||
If you want to use `WebTestClient` or REST Assured rather than MockMvc, add a dependency on `spring-restdocs-webtestclient` or `spring-restdocs-restassured` respectively instead.
|
||||
<5> Configure a property to define the output location for generated snippets.
|
||||
<6> Configure the `test` task to add the snippets directory as an output.
|
||||
<7> Configure the `asciidoctor` task.
|
||||
@@ -232,7 +245,7 @@ The following listings show how to do so in both Maven and Gradle:
|
||||
|
||||
[[getting-started-documentation-snippets]]
|
||||
=== Generating Documentation Snippets
|
||||
Spring REST Docs uses Spring MVC's {spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework] or Spring WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`] to make requests to the service that you are documenting.
|
||||
Spring REST Docs uses Spring MVC's {spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework] or Spring WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`], or https://rest-assured.io[REST Assured] to make requests to the service that you are documenting.
|
||||
It then produces documentation snippets for the request and the resulting response.
|
||||
|
||||
|
||||
@@ -280,7 +293,7 @@ The following example shows how to do so:
|
||||
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("custom");
|
||||
----
|
||||
|
||||
Next, you must provide an `@Before` method to configure MockMvc or WebTestClient.
|
||||
Next, you must provide an `@Before` method to configure MockMvc or WebTestClient, or REST Assured.
|
||||
The following examples show how to do so:
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
@@ -299,6 +312,14 @@ include::{examples-dir}/com/example/webtestclient/ExampleApplicationTests.java[t
|
||||
<1> The `WebTestClient` instance is configured by adding a `WebTestclientRestDocumentationConfigurer` as an `ExchangeFilterFunction`.
|
||||
You can obtain an instance of this class from the static `documentationConfiguration()` method on `org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/ExampleApplicationTests.java[tags=setup]
|
||||
----
|
||||
<1> REST Assured is configured by adding a `RestAssuredRestDocumentationConfigurer` as a `Filter`.
|
||||
You can obtain an instance of this class from the static `documentationConfiguration()` method on `RestAssuredRestDocumentation` in the `org.springframework.restdocs.restassured` package.
|
||||
|
||||
The configurer applies sensible defaults and also provides an API for customizing the configuration.
|
||||
See the <<configuration, configuration section>> for more information.
|
||||
|
||||
@@ -350,7 +371,7 @@ public class JUnit5ExampleTests {
|
||||
}
|
||||
----
|
||||
|
||||
Next, you must provide a `@BeforeEach` method to configure MockMvc or WebTestClient.
|
||||
Next, you must provide a `@BeforeEach` method to configure MockMvc or WebTestClient, or REST Assured.
|
||||
The following listings show how to do so:
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
@@ -369,6 +390,14 @@ include::{examples-dir}/com/example/webtestclient/ExampleApplicationJUnit5Tests.
|
||||
<1> The `WebTestClient` instance is configured by adding a `WebTestClientRestDocumentationConfigurer` as an `ExchangeFilterFunction`.
|
||||
You can obtain an instance of this class from the static `documentationConfiguration()` method on `org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/ExampleApplicationJUnit5Tests.java[tags=setup]
|
||||
----
|
||||
<1> REST Assured is configured by adding a `RestAssuredRestDocumentationConfigurer` as a `Filter`.
|
||||
You can obtain an instance of this class from the static `documentationConfiguration()` method on `RestAssuredRestDocumentation` in the `org.springframework.restdocs.restassured` package.
|
||||
|
||||
The configurer applies sensible defaults and also provides an API for customizing the configuration.
|
||||
See the <<configuration, configuration section>> for more information.
|
||||
|
||||
@@ -391,7 +420,7 @@ private ManualRestDocumentation restDocumentation = new ManualRestDocumentation(
|
||||
----
|
||||
|
||||
Secondly, you must call `ManualRestDocumentation.beforeTest(Class, String)` before each test.
|
||||
You can do so as part of the method that configures MockMvc or WebTestClient.
|
||||
You can do so as part of the method that configures MockMvc, WebTestClient, or REST Assured.
|
||||
The following examples show how to do so:
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
@@ -406,6 +435,12 @@ include::{examples-dir}/com/example/mockmvc/ExampleApplicationTestNgTests.java[t
|
||||
include::{examples-dir}/com/example/webtestclient/ExampleApplicationTestNgTests.java[tags=setup]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/ExampleApplicationTestNgTests.java[tags=setup]
|
||||
----
|
||||
|
||||
Finally, you must call `ManualRestDocumentation.afterTest` after each test.
|
||||
The following example shows how to do so with TestNG:
|
||||
|
||||
@@ -444,6 +479,19 @@ include::{examples-dir}/com/example/webtestclient/InvokeService.java[tags=invoke
|
||||
The snippets are written by a `Consumer` of the `ExchangeResult`.
|
||||
You can obtain such a consumer from the static `document` method on `org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation`.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/InvokeService.java[tags=invoke-service]
|
||||
----
|
||||
<1> Apply the specification that was initialized in the `@Before` method.
|
||||
<2> Indicate that an `application/json` response is required.
|
||||
<3> Document the call to the service, writing the snippets into a directory named `index` (which is located beneath the configured output directory).
|
||||
The snippets are written by a `RestDocumentationFilter`.
|
||||
You can obtain an instance of this class from the static `document` method on `RestAssuredRestDocumentation` in the `org.springframework.restdocs.restassured` package.
|
||||
<4> Invoke the root (`/`) of the service.
|
||||
<5> Assert that the service produce the expected response.
|
||||
|
||||
By default, six snippets are written:
|
||||
|
||||
* `<output-directory>/index/curl-request.adoc`
|
||||
|
||||
@@ -9,7 +9,7 @@ To this end, Spring REST Docs uses https://asciidoctor.org[Asciidoctor] by defau
|
||||
Asciidoctor processes plain text and produces HTML, styled and laid out to suit your needs.
|
||||
If you prefer, you can also configure Spring REST Docs to use Markdown.
|
||||
|
||||
Spring REST Docs uses snippets produced by tests written with Spring MVC's {spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework] or Spring WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`].
|
||||
Spring REST Docs uses snippets produced by tests written with Spring MVC's {spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework], Spring WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`] or http://rest-assured.io[REST Assured 4].
|
||||
This test-driven approach helps to guarantee the accuracy of your service's documentation.
|
||||
If a snippet is incorrect, the test that produces it fails.
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class CustomDefaultOperationPreprocessors {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private RequestSpecification spec;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// tag::custom-default-operation-preprocessors[]
|
||||
this.spec = new RequestSpecBuilder()
|
||||
.addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
|
||||
.withRequestDefaults(removeHeaders("Foo")) // <1>
|
||||
.withResponseDefaults(prettyPrint())) // <2>
|
||||
.build();
|
||||
// end::custom-default-operation-preprocessors[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
|
||||
import static org.springframework.restdocs.cli.CliDocumentation.curlRequest;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class CustomDefaultSnippets {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private RequestSpecification spec;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// tag::custom-default-snippets[]
|
||||
this.spec = new RequestSpecBuilder()
|
||||
.addFilter(documentationConfiguration(this.restDocumentation).snippets().withDefaults(curlRequest()))
|
||||
.build();
|
||||
// end::custom-default-snippets[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class CustomEncoding {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private RequestSpecification spec;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// tag::custom-encoding[]
|
||||
this.spec = new RequestSpecBuilder()
|
||||
.addFilter(documentationConfiguration(this.restDocumentation).snippets().withEncoding("ISO-8859-1"))
|
||||
.build();
|
||||
// end::custom-encoding[]
|
||||
}
|
||||
|
||||
}
|
||||
45
docs/src/test/java/com/example/restassured/CustomFormat.java
Normal file
45
docs/src/test/java/com/example/restassured/CustomFormat.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class CustomFormat {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private RequestSpecification spec;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// tag::custom-format[]
|
||||
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation).snippets()
|
||||
.withTemplateFormat(TemplateFormats.markdown())).build();
|
||||
// end::custom-format[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class EveryTestPreprocessing {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
// tag::setup[]
|
||||
private RequestSpecification spec;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.spec = new RequestSpecBuilder()
|
||||
.addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
|
||||
.withRequestDefaults(removeHeaders("Foo")) // <1>
|
||||
.withResponseDefaults(prettyPrint())) // <2>
|
||||
.build();
|
||||
}
|
||||
// end::setup[]
|
||||
|
||||
public void use() throws Exception {
|
||||
// tag::use[]
|
||||
RestAssured.given(this.spec)
|
||||
.filter(document("index", links(linkWithRel("self").description("Canonical self link")))).when()
|
||||
.get("/").then().assertThat().statusCode(is(200));
|
||||
// end::use[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationContextProvider;
|
||||
import org.springframework.restdocs.RestDocumentationExtension;
|
||||
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
@ExtendWith(RestDocumentationExtension.class)
|
||||
public class ExampleApplicationJUnit5Tests {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
// tag::setup[]
|
||||
private RequestSpecification spec;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(RestDocumentationContextProvider restDocumentation) {
|
||||
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(restDocumentation)) // <1>
|
||||
.build();
|
||||
}
|
||||
// end::setup[]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
|
||||
import org.springframework.restdocs.ManualRestDocumentation;
|
||||
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class ExampleApplicationTestNgTests {
|
||||
|
||||
private final ManualRestDocumentation restDocumentation = new ManualRestDocumentation();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
// tag::setup[]
|
||||
private RequestSpecification spec;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp(Method method) {
|
||||
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation)).build();
|
||||
this.restDocumentation.beforeTest(getClass(), method.getName());
|
||||
}
|
||||
|
||||
// end::setup[]
|
||||
|
||||
// tag::teardown[]
|
||||
@AfterMethod
|
||||
public void tearDown() {
|
||||
this.restDocumentation.afterTest();
|
||||
}
|
||||
// end::teardown[]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class ExampleApplicationTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
// tag::setup[]
|
||||
private RequestSpecification spec;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation)) // <1>
|
||||
.build();
|
||||
}
|
||||
// end::setup[]
|
||||
|
||||
}
|
||||
48
docs/src/test/java/com/example/restassured/HttpHeaders.java
Normal file
48
docs/src/test/java/com/example/restassured/HttpHeaders.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class HttpHeaders {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void headers() throws Exception {
|
||||
// tag::headers[]
|
||||
RestAssured.given(this.spec).filter(document("headers", requestHeaders(// <1>
|
||||
headerWithName("Authorization").description("Basic auth credentials")), // <2>
|
||||
responseHeaders(// <3>
|
||||
headerWithName("X-RateLimit-Limit")
|
||||
.description("The total number of requests permitted per period"),
|
||||
headerWithName("X-RateLimit-Remaining")
|
||||
.description("Remaining requests permitted in current period"),
|
||||
headerWithName("X-RateLimit-Reset")
|
||||
.description("Time at which the rate limit period will reset"))))
|
||||
.header("Authorization", "Basic dXNlcjpzZWNyZXQ=") // <4>
|
||||
.when().get("/people").then().assertThat().statusCode(is(200));
|
||||
// end::headers[]
|
||||
}
|
||||
|
||||
}
|
||||
51
docs/src/test/java/com/example/restassured/Hypermedia.java
Normal file
51
docs/src/test/java/com/example/restassured/Hypermedia.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.halLinks;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class Hypermedia {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void defaultExtractor() throws Exception {
|
||||
// tag::links[]
|
||||
RestAssured.given(this.spec).accept("application/json").filter(document("index", links(// <1>
|
||||
linkWithRel("alpha").description("Link to the alpha resource"), // <2>
|
||||
linkWithRel("bravo").description("Link to the bravo resource")))) // <3>
|
||||
.get("/").then().assertThat().statusCode(is(200));
|
||||
// end::links[]
|
||||
}
|
||||
|
||||
public void explicitExtractor() throws Exception {
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
// tag::explicit-extractor[]
|
||||
.filter(document("index", links(halLinks(), // <1>
|
||||
linkWithRel("alpha").description("Link to the alpha resource"),
|
||||
linkWithRel("bravo").description("Link to the bravo resource"))))
|
||||
// end::explicit-extractor[]
|
||||
.get("/").then().assertThat().statusCode(is(200));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class InvokeService {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void invokeService() throws Exception {
|
||||
// tag::invoke-service[]
|
||||
RestAssured.given(this.spec) // <1>
|
||||
.accept("application/json") // <2>
|
||||
.filter(document("index")) // <3>
|
||||
.when().get("/") // <4>
|
||||
.then().assertThat().statusCode(is(200)); // <5>
|
||||
// end::invoke-service[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
public class ParameterizedOutput {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private RequestSpecification spec;
|
||||
|
||||
// tag::parameterized-output[]
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation))
|
||||
.addFilter(document("{method-name}/{step}")).build();
|
||||
}
|
||||
// end::parameterized-output[]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class PathParameters {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void pathParametersSnippet() throws Exception {
|
||||
// tag::path-parameters[]
|
||||
RestAssured.given(this.spec).filter(document("locations", pathParameters(// <1>
|
||||
parameterWithName("latitude").description("The location's latitude"), // <2>
|
||||
parameterWithName("longitude").description("The location's longitude")))) // <3>
|
||||
.when().get("/locations/{latitude}/{longitude}", 51.5072, 0.1275) // <4>
|
||||
.then().assertThat().statusCode(is(200));
|
||||
// end::path-parameters[]
|
||||
}
|
||||
|
||||
}
|
||||
115
docs/src/test/java/com/example/restassured/Payload.java
Normal file
115
docs/src/test/java/com/example/restassured/Payload.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||
import org.springframework.restdocs.payload.JsonFieldType;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseBody;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
import static org.springframework.restdocs.snippet.Attributes.attributes;
|
||||
import static org.springframework.restdocs.snippet.Attributes.key;
|
||||
|
||||
public class Payload {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void response() throws Exception {
|
||||
// tag::response[]
|
||||
RestAssured.given(this.spec).accept("application/json").filter(document("user", responseFields(// <1>
|
||||
fieldWithPath("contact.name").description("The user's name"), // <2>
|
||||
fieldWithPath("contact.email").description("The user's email address")))) // <3>
|
||||
.when().get("/user/5").then().assertThat().statusCode(is(200));
|
||||
// end::response[]
|
||||
}
|
||||
|
||||
public void subsection() throws Exception {
|
||||
// tag::subsection[]
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
.filter(document("user",
|
||||
responseFields(subsectionWithPath("contact").description("The user's contact details")))) // <1>
|
||||
.when().get("/user/5").then().assertThat().statusCode(is(200));
|
||||
// end::subsection[]
|
||||
}
|
||||
|
||||
public void explicitType() throws Exception {
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
// tag::explicit-type[]
|
||||
.filter(document("user", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) // <1>
|
||||
.description("The user's email address"))))
|
||||
// end::explicit-type[]
|
||||
.when().get("/user/5").then().assertThat().statusCode(is(200));
|
||||
}
|
||||
|
||||
public void constraints() throws Exception {
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
// tag::constraints[]
|
||||
.filter(document("create-user",
|
||||
requestFields(attributes(key("title").value("Fields for user creation")), // <1>
|
||||
fieldWithPath("name").description("The user's name")
|
||||
.attributes(key("constraints").value("Must not be null. Must not be empty")), // <2>
|
||||
fieldWithPath("email").description("The user's email address")
|
||||
.attributes(key("constraints").value("Must be a valid email address"))))) // <3>
|
||||
// end::constraints[]
|
||||
.when().post("/users").then().assertThat().statusCode(is(200));
|
||||
}
|
||||
|
||||
public void descriptorReuse() throws Exception {
|
||||
FieldDescriptor[] book = new FieldDescriptor[] { fieldWithPath("title").description("Title of the book"),
|
||||
fieldWithPath("author").description("Author of the book") };
|
||||
|
||||
// tag::single-book[]
|
||||
RestAssured.given(this.spec).accept("application/json").filter(document("book", responseFields(book))) // <1>
|
||||
.when().get("/books/1").then().assertThat().statusCode(is(200));
|
||||
// end::single-book[]
|
||||
|
||||
// tag::book-array[]
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
.filter(document("books", responseFields(fieldWithPath("[]").description("An array of books")) // <1>
|
||||
.andWithPrefix("[].", book))) // <2>
|
||||
.when().get("/books").then().assertThat().statusCode(is(200));
|
||||
// end::book-array[]
|
||||
}
|
||||
|
||||
public void fieldsSubsection() throws Exception {
|
||||
// tag::fields-subsection[]
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
.filter(document("location", responseFields(beneathPath("weather.temperature"), // <1>
|
||||
fieldWithPath("high").description("The forecast high in degrees celcius"), // <2>
|
||||
fieldWithPath("low").description("The forecast low in degrees celcius"))))
|
||||
.when().get("/locations/1").then().assertThat().statusCode(is(200));
|
||||
// end::fields-subsection[]
|
||||
}
|
||||
|
||||
public void bodySubsection() throws Exception {
|
||||
// tag::body-subsection[]
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
.filter(document("location", responseBody(beneathPath("weather.temperature")))) // <1>
|
||||
.when().get("/locations/1").then().assertThat().statusCode(is(200));
|
||||
// end::body-subsection[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
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.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class PerTestPreprocessing {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void general() throws Exception {
|
||||
// tag::preprocessing[]
|
||||
RestAssured.given(this.spec).filter(document("index", preprocessRequest(removeHeaders("Foo")), // <1>
|
||||
preprocessResponse(prettyPrint()))) // <2>
|
||||
.when().get("/").then().assertThat().statusCode(is(200));
|
||||
// end::preprocessing[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class RequestParameters {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void getQueryStringSnippet() throws Exception {
|
||||
// tag::request-parameters-query-string[]
|
||||
RestAssured.given(this.spec).filter(document("users", requestParameters(// <1>
|
||||
parameterWithName("page").description("The page to retrieve"), // <2>
|
||||
parameterWithName("per_page").description("Entries per page")))) // <3>
|
||||
.when().get("/users?page=2&per_page=100") // <4>
|
||||
.then().assertThat().statusCode(is(200));
|
||||
// end::request-parameters-query-string[]
|
||||
}
|
||||
|
||||
public void postFormDataSnippet() throws Exception {
|
||||
// tag::request-parameters-form-data[]
|
||||
RestAssured.given(this.spec)
|
||||
.filter(document("create-user",
|
||||
requestParameters(parameterWithName("username").description("The user's username"))))
|
||||
.formParam("username", "Tester") // <1>
|
||||
.when().post("/users") // <2>
|
||||
.then().assertThat().statusCode(is(200));
|
||||
// end::request-parameters-form-data[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartBody;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class RequestPartPayload {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void fields() throws Exception {
|
||||
// tag::fields[]
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put("version", "1.0");
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
.filter(document("image-upload", requestPartFields("metadata", // <1>
|
||||
fieldWithPath("version").description("The version of the image")))) // <2>
|
||||
.when().multiPart("image", new File("image.png"), "image/png").multiPart("metadata", metadata)
|
||||
.post("images").then().assertThat().statusCode(is(200));
|
||||
// end::fields[]
|
||||
}
|
||||
|
||||
public void body() throws Exception {
|
||||
// tag::body[]
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put("version", "1.0");
|
||||
RestAssured.given(this.spec).accept("application/json")
|
||||
.filter(document("image-upload", requestPartBody("metadata"))) // <1>
|
||||
.when().multiPart("image", new File("image.png"), "image/png").multiPart("metadata", metadata)
|
||||
.post("images").then().assertThat().statusCode(is(200));
|
||||
// end::body[]
|
||||
}
|
||||
|
||||
}
|
||||
41
docs/src/test/java/com/example/restassured/RequestParts.java
Normal file
41
docs/src/test/java/com/example/restassured/RequestParts.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParts;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class RequestParts {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void upload() throws Exception {
|
||||
// tag::request-parts[]
|
||||
RestAssured.given(this.spec).filter(document("users", requestParts(// <1>
|
||||
partWithName("file").description("The file to upload")))) // <2>
|
||||
.multiPart("file", "example") // <3>
|
||||
.when().post("/upload") // <4>
|
||||
.then().statusCode(is(200));
|
||||
// end::request-parts[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2014-2021 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import com.example.SnippetReuse;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
|
||||
public class RestAssuredSnippetReuse extends SnippetReuse {
|
||||
|
||||
private RequestSpecification spec;
|
||||
|
||||
public void documentation() throws Exception {
|
||||
// tag::use[]
|
||||
RestAssured.given(this.spec).accept("application/json").filter(document("example", this.pagingLinks.and(// <1>
|
||||
linkWithRel("alpha").description("Link to the alpha resource"),
|
||||
linkWithRel("bravo").description("Link to the bravo resource")))).get("/").then().assertThat()
|
||||
.statusCode(is(200));
|
||||
// end::use[]
|
||||
}
|
||||
|
||||
}
|
||||
63
samples/rest-assured/build.gradle
Normal file
63
samples/rest-assured/build.gradle
Normal file
@@ -0,0 +1,63 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "org.asciidoctor.jvm.convert" version "3.3.2"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://repo.spring.io/milestone' }
|
||||
maven { url 'https://repo.spring.io/snapshot' }
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
|
||||
ext {
|
||||
restdocsVersion = '3.0.0-SNAPSHOT'
|
||||
snippetsDir = file('build/generated-snippets')
|
||||
}
|
||||
|
||||
configurations {
|
||||
asciidoctorExtensions
|
||||
}
|
||||
|
||||
dependencies {
|
||||
asciidoctorExtensions "org.springframework.restdocs:spring-restdocs-asciidoctor:$restdocsVersion"
|
||||
|
||||
implementation platform("org.springframework:spring-framework-bom:6.0.0-M2")
|
||||
implementation 'io.projectreactor.netty:reactor-netty-http:1.0.15'
|
||||
implementation 'org.springframework:spring-context'
|
||||
implementation 'org.springframework:spring-webflux'
|
||||
|
||||
|
||||
testImplementation 'io.rest-assured:rest-assured:4.5.0'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.0'
|
||||
testImplementation "org.springframework.restdocs:spring-restdocs-restassured:$restdocsVersion"
|
||||
testImplementation 'org.springframework:spring-test'
|
||||
testImplementation('org.junit.vintage:junit-vintage-engine') {
|
||||
exclude group: 'org.hamcrest', module: 'hamcrest-core'
|
||||
}
|
||||
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.0'
|
||||
}
|
||||
|
||||
test {
|
||||
outputs.dir snippetsDir
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
configurations "asciidoctorExtensions"
|
||||
inputs.dir snippetsDir
|
||||
dependsOn test
|
||||
}
|
||||
|
||||
jar {
|
||||
dependsOn asciidoctor
|
||||
from ("${asciidoctor.outputDir}/html5") {
|
||||
into 'static/docs'
|
||||
}
|
||||
}
|
||||
BIN
samples/rest-assured/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
samples/rest-assured/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
samples/rest-assured/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
samples/rest-assured/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
185
samples/rest-assured/gradlew
vendored
Executable file
185
samples/rest-assured/gradlew
vendored
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
samples/rest-assured/gradlew.bat
vendored
Normal file
89
samples/rest-assured/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
0
samples/rest-assured/settings.gradle
Normal file
0
samples/rest-assured/settings.gradle
Normal file
26
samples/rest-assured/src/docs/asciidoc/index.adoc
Normal file
26
samples/rest-assured/src/docs/asciidoc/index.adoc
Normal file
@@ -0,0 +1,26 @@
|
||||
= Spring REST Docs REST Assured Sample
|
||||
Andy Wilkinson;
|
||||
:doctype: book
|
||||
:icons: font
|
||||
:source-highlighter: highlightjs
|
||||
|
||||
Sample application demonstrating how to use Spring REST Docs with REST Assured.
|
||||
|
||||
`SampleRestAssuredApplicationTests` makes a call to a very simple service. The service
|
||||
that is being tested is running on a random port on `localhost`. The tests make use of a
|
||||
preprocessor to modify the request so that it appears to have been sent to
|
||||
`https://api.example.com`. If your service includes URIs in its responses, for example
|
||||
because it uses hypermedia, similar preprocessing can be applied to the response before
|
||||
it is documented.
|
||||
|
||||
Three snippets are produced. One showing how to make a request using cURL:
|
||||
|
||||
include::{snippets}/sample/curl-request.adoc[]
|
||||
|
||||
One showing the HTTP request:
|
||||
|
||||
include::{snippets}/sample/http-request.adoc[]
|
||||
|
||||
And one showing the HTTP response:
|
||||
|
||||
include::{snippets}/sample/http-response.adoc[]
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import reactor.netty.DisposableServer;
|
||||
import reactor.netty.http.server.HttpServer;
|
||||
|
||||
@EnableWebFlux
|
||||
@Configuration
|
||||
class SampleRestAssuredApplication {
|
||||
|
||||
@Bean
|
||||
RouterFunction<ServerResponse> routerFunction() {
|
||||
return RouterFunctions.route(RequestPredicates.GET("/"),
|
||||
(request) -> ServerResponse.status(HttpStatus.OK).bodyValue("Hello, World"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
WebServer webServer(RouterFunction<ServerResponse> routerFunction) {
|
||||
return new WebServer(routerFunction);
|
||||
}
|
||||
|
||||
static class WebServer implements DisposableBean {
|
||||
|
||||
private final DisposableServer httpServer;
|
||||
|
||||
WebServer(RouterFunction<?> routerFunction) {
|
||||
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(RouterFunctions.toHttpHandler(routerFunction));
|
||||
HttpServer httpServer = HttpServer.create().handle(adapter);
|
||||
this.httpServer = httpServer.bindNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
this.httpServer.disposeNow();
|
||||
}
|
||||
|
||||
int getPort() {
|
||||
return ((InetSocketAddress)this.httpServer.address()).getPort();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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 com.example.restassured;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
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.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.example.restassured.SampleRestAssuredApplication.WebServer;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
|
||||
@ContextConfiguration(classes = SampleRestAssuredApplication.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SampleRestAssuredApplicationTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
private RequestSpecification documentationSpec;
|
||||
|
||||
@Autowired
|
||||
private WebServer webServer;
|
||||
|
||||
private int port;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.documentationSpec = new RequestSpecBuilder()
|
||||
.addFilter(documentationConfiguration(restDocumentation)).build();
|
||||
this.port = webServer.getPort();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sample() throws Exception {
|
||||
given(this.documentationSpec)
|
||||
.accept("text/plain")
|
||||
.filter(document("sample",
|
||||
preprocessRequest(modifyUris()
|
||||
.scheme("https")
|
||||
.host("api.example.com")
|
||||
.removePort())))
|
||||
.when()
|
||||
.port(this.port)
|
||||
.get("/")
|
||||
.then()
|
||||
.assertThat().statusCode(is(200));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,4 +39,5 @@ include "spring-restdocs-asciidoctor"
|
||||
include "spring-restdocs-core"
|
||||
include "spring-restdocs-mockmvc"
|
||||
include "spring-restdocs-platform"
|
||||
include "spring-restdocs-restassured"
|
||||
include "spring-restdocs-webtestclient"
|
||||
|
||||
@@ -12,6 +12,7 @@ dependencies {
|
||||
api("jakarta.servlet:jakarta.servlet-api:5.0.0")
|
||||
api("jakarta.validation:jakarta.validation-api:3.0.0")
|
||||
api("junit:junit:4.12")
|
||||
api("io.rest-assured:rest-assured:4.5.0")
|
||||
api("org.apache.pdfbox:pdfbox:2.0.7")
|
||||
api("org.asciidoctor:asciidoctorj:2.5.2")
|
||||
api("org.asciidoctor:asciidoctorj-pdf:1.6.0")
|
||||
|
||||
24
spring-restdocs-restassured/build.gradle
Normal file
24
spring-restdocs-restassured/build.gradle
Normal file
@@ -0,0 +1,24 @@
|
||||
plugins {
|
||||
id "java-library"
|
||||
id "maven-publish"
|
||||
}
|
||||
|
||||
description = "Spring REST Docs REST Assured"
|
||||
|
||||
dependencies {
|
||||
api(project(":spring-restdocs-core"))
|
||||
api("io.rest-assured:rest-assured") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
}
|
||||
implementation("org.springframework:spring-web")
|
||||
|
||||
internal(platform(project(":spring-restdocs-platform")))
|
||||
|
||||
testImplementation(testFixtures(project(":spring-restdocs-core")))
|
||||
testImplementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
testImplementation("junit:junit")
|
||||
testImplementation("org.apache.tomcat.embed:tomcat-embed-core:10.0.11")
|
||||
testImplementation("org.assertj:assertj-core")
|
||||
testImplementation("org.hamcrest:hamcrest-library")
|
||||
testImplementation("org.mockito:mockito-core")
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import io.restassured.filter.Filter;
|
||||
import io.restassured.filter.FilterContext;
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.specification.FilterableRequestSpecification;
|
||||
import io.restassured.specification.FilterableResponseSpecification;
|
||||
|
||||
import org.springframework.restdocs.config.OperationPreprocessorsConfigurer;
|
||||
|
||||
/**
|
||||
* A configurer that can be used to configure the operation preprocessors when using REST
|
||||
* Assured.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class RestAssuredOperationPreprocessorsConfigurer extends
|
||||
OperationPreprocessorsConfigurer<RestAssuredRestDocumentationConfigurer, RestAssuredOperationPreprocessorsConfigurer>
|
||||
implements Filter {
|
||||
|
||||
RestAssuredOperationPreprocessorsConfigurer(RestAssuredRestDocumentationConfigurer parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec,
|
||||
FilterContext context) {
|
||||
return and().filter(requestSpec, responseSpec, context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import io.restassured.http.Cookie;
|
||||
import io.restassured.http.Header;
|
||||
import io.restassured.specification.FilterableRequestSpecification;
|
||||
import io.restassured.specification.MultiPartSpecification;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.restdocs.operation.OperationRequest;
|
||||
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 org.springframework.restdocs.operation.RequestCookie;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* A converter for creating an {@link OperationRequest} from a REST Assured
|
||||
* {@link FilterableRequestSpecification}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class RestAssuredRequestConverter implements RequestConverter<FilterableRequestSpecification> {
|
||||
|
||||
@Override
|
||||
public OperationRequest convert(FilterableRequestSpecification requestSpec) {
|
||||
return new OperationRequestFactory().create(URI.create(requestSpec.getURI()),
|
||||
HttpMethod.valueOf(requestSpec.getMethod()), extractContent(requestSpec), extractHeaders(requestSpec),
|
||||
extractParameters(requestSpec), extractParts(requestSpec), extractCookies(requestSpec));
|
||||
}
|
||||
|
||||
private Collection<RequestCookie> extractCookies(FilterableRequestSpecification requestSpec) {
|
||||
Collection<RequestCookie> cookies = new ArrayList<>();
|
||||
for (Cookie cookie : requestSpec.getCookies()) {
|
||||
cookies.add(new RequestCookie(cookie.getName(), cookie.getValue()));
|
||||
}
|
||||
return cookies;
|
||||
}
|
||||
|
||||
private byte[] extractContent(FilterableRequestSpecification requestSpec) {
|
||||
return convertContent(requestSpec.getBody());
|
||||
}
|
||||
|
||||
private byte[] convertContent(Object content) {
|
||||
if (content instanceof String) {
|
||||
return ((String) content).getBytes();
|
||||
}
|
||||
else if (content instanceof byte[]) {
|
||||
return (byte[]) content;
|
||||
}
|
||||
else if (content instanceof File) {
|
||||
return copyToByteArray((File) content);
|
||||
}
|
||||
else if (content instanceof InputStream) {
|
||||
return copyToByteArray((InputStream) content);
|
||||
}
|
||||
else if (content == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Unsupported request content: " + content.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] copyToByteArray(File file) {
|
||||
try {
|
||||
return FileCopyUtils.copyToByteArray(file);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to read content from file " + file, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] copyToByteArray(InputStream inputStream) {
|
||||
try {
|
||||
inputStream.reset();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot read content from input stream " + inputStream + " due to reset() failure");
|
||||
}
|
||||
try {
|
||||
return StreamUtils.copyToByteArray(inputStream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to read content from input stream " + inputStream, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpHeaders extractHeaders(FilterableRequestSpecification requestSpec) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
for (Header header : requestSpec.getHeaders()) {
|
||||
if (!isAllMediaTypesAcceptHeader(header)) {
|
||||
httpHeaders.add(header.getName(), header.getValue());
|
||||
}
|
||||
}
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
private boolean isAllMediaTypesAcceptHeader(Header header) {
|
||||
return HttpHeaders.ACCEPT.equals(header.getName()) && "*/*".equals(header.getValue());
|
||||
}
|
||||
|
||||
private Parameters extractParameters(FilterableRequestSpecification requestSpec) {
|
||||
Parameters parameters = new Parameters();
|
||||
for (Entry<String, ?> entry : requestSpec.getQueryParams().entrySet()) {
|
||||
if (entry.getValue() instanceof Collection) {
|
||||
Collection<?> queryParams = ((Collection<?>) entry.getValue());
|
||||
for (Object queryParam : queryParams) {
|
||||
parameters.add(entry.getKey(), queryParam.toString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
parameters.add(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
for (Entry<String, ?> entry : requestSpec.getRequestParams().entrySet()) {
|
||||
parameters.add(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
for (Entry<String, ?> entry : requestSpec.getFormParams().entrySet()) {
|
||||
parameters.add(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private Collection<OperationRequestPart> extractParts(FilterableRequestSpecification requestSpec) {
|
||||
List<OperationRequestPart> parts = new ArrayList<>();
|
||||
for (MultiPartSpecification multiPartSpec : requestSpec.getMultiPartParams()) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType((multiPartSpec.getMimeType() != null)
|
||||
? MediaType.parseMediaType(multiPartSpec.getMimeType()) : MediaType.TEXT_PLAIN);
|
||||
parts.add(new OperationRequestPartFactory().create(multiPartSpec.getControlName(),
|
||||
multiPartSpec.getFileName(), convertContent(multiPartSpec.getContent()), headers));
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import io.restassured.http.Header;
|
||||
import io.restassured.response.Response;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.restdocs.operation.OperationResponse;
|
||||
import org.springframework.restdocs.operation.OperationResponseFactory;
|
||||
import org.springframework.restdocs.operation.ResponseConverter;
|
||||
|
||||
/**
|
||||
* A converter for creating an {@link OperationResponse} from a REST Assured
|
||||
* {@link Response}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class RestAssuredResponseConverter implements ResponseConverter<Response> {
|
||||
|
||||
@Override
|
||||
public OperationResponse convert(Response response) {
|
||||
return new OperationResponseFactory().create(response.getStatusCode(), extractHeaders(response),
|
||||
extractContent(response));
|
||||
}
|
||||
|
||||
private HttpHeaders extractHeaders(Response response) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
for (Header header : response.getHeaders()) {
|
||||
httpHeaders.add(header.getName(), header.getValue());
|
||||
}
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
private byte[] extractContent(Response response) {
|
||||
return response.getBody().asByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationContextProvider;
|
||||
import org.springframework.restdocs.generate.RestDocumentationGenerator;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
|
||||
import org.springframework.restdocs.snippet.Snippet;
|
||||
|
||||
/**
|
||||
* Static factory methods for documenting RESTful APIs using REST Assured.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public abstract class RestAssuredRestDocumentation {
|
||||
|
||||
private static final RestAssuredRequestConverter REQUEST_CONVERTER = new RestAssuredRequestConverter();
|
||||
|
||||
private static final RestAssuredResponseConverter RESPONSE_CONVERTER = new RestAssuredResponseConverter();
|
||||
|
||||
private RestAssuredRestDocumentation() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets}.
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param snippets the snippets that will document the API call
|
||||
* @return a {@link RestDocumentationFilter} that will produce the documentation
|
||||
*/
|
||||
public static RestDocumentationFilter document(String identifier, Snippet... snippets) {
|
||||
return new RestDocumentationFilter(
|
||||
new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets} in addition to any default snippets. The given
|
||||
* {@code requestPreprocessor} is applied to the request before it is documented.
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param requestPreprocessor the request preprocessor
|
||||
* @param snippets the snippets
|
||||
* @return a {@link RestDocumentationFilter} that will produce the documentation
|
||||
*/
|
||||
public static RestDocumentationFilter document(String identifier, OperationRequestPreprocessor requestPreprocessor,
|
||||
Snippet... snippets) {
|
||||
return new RestDocumentationFilter(new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
|
||||
RESPONSE_CONVERTER, requestPreprocessor, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets} in addition to any default snippets. The given
|
||||
* {@code responsePreprocessor} is applied to the request before it is documented.
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param responsePreprocessor the response preprocessor
|
||||
* @param snippets the snippets
|
||||
* @return a {@link RestDocumentationFilter} that will produce the documentation
|
||||
*/
|
||||
public static RestDocumentationFilter document(String identifier,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationFilter(new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
|
||||
RESPONSE_CONVERTER, responsePreprocessor, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets} in addition to any default snippets. The given
|
||||
* {@code requestPreprocessor} and {@code responsePreprocessor} are applied to the
|
||||
* request and response respectively before they are documented.
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param requestPreprocessor the request preprocessor
|
||||
* @param responsePreprocessor the response preprocessor
|
||||
* @param snippets the snippets
|
||||
* @return a {@link RestDocumentationFilter} that will produce the documentation
|
||||
*/
|
||||
public static RestDocumentationFilter document(String identifier, OperationRequestPreprocessor requestPreprocessor,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationFilter(new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
|
||||
RESPONSE_CONVERTER, requestPreprocessor, responsePreprocessor, snippets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to a {@link RestAssuredRestDocumentationConfigurer} that can be
|
||||
* used to configure Spring REST Docs using the given {@code contextProvider}.
|
||||
* @param contextProvider the context provider
|
||||
* @return the configurer
|
||||
*/
|
||||
public static RestAssuredRestDocumentationConfigurer documentationConfiguration(
|
||||
RestDocumentationContextProvider contextProvider) {
|
||||
return new RestAssuredRestDocumentationConfigurer(contextProvider);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.restassured.filter.Filter;
|
||||
import io.restassured.filter.FilterContext;
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.specification.FilterableRequestSpecification;
|
||||
import io.restassured.specification.FilterableResponseSpecification;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationContext;
|
||||
import org.springframework.restdocs.RestDocumentationContextProvider;
|
||||
import org.springframework.restdocs.config.RestDocumentationConfigurer;
|
||||
|
||||
/**
|
||||
* A REST Assured-specific {@link RestDocumentationConfigurer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Filip Hrisafov
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public final class RestAssuredRestDocumentationConfigurer extends
|
||||
RestDocumentationConfigurer<RestAssuredSnippetConfigurer, RestAssuredOperationPreprocessorsConfigurer, RestAssuredRestDocumentationConfigurer>
|
||||
implements Filter {
|
||||
|
||||
private final RestAssuredSnippetConfigurer snippetConfigurer = new RestAssuredSnippetConfigurer(this);
|
||||
|
||||
private final RestAssuredOperationPreprocessorsConfigurer operationPreprocessorsConfigurer = new RestAssuredOperationPreprocessorsConfigurer(
|
||||
this);
|
||||
|
||||
private final RestDocumentationContextProvider contextProvider;
|
||||
|
||||
RestAssuredRestDocumentationConfigurer(RestDocumentationContextProvider contextProvider) {
|
||||
this.contextProvider = contextProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestAssuredSnippetConfigurer snippets() {
|
||||
return this.snippetConfigurer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestAssuredOperationPreprocessorsConfigurer operationPreprocessors() {
|
||||
return this.operationPreprocessorsConfigurer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec,
|
||||
FilterContext filterContext) {
|
||||
RestDocumentationContext context = this.contextProvider.beforeOperation();
|
||||
filterContext.setValue(RestDocumentationContext.class.getName(), context);
|
||||
Map<String, Object> configuration = new HashMap<>();
|
||||
filterContext.setValue(RestDocumentationFilter.CONTEXT_KEY_CONFIGURATION, configuration);
|
||||
apply(configuration, context);
|
||||
return filterContext.next(requestSpec, responseSpec);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import io.restassured.filter.Filter;
|
||||
import io.restassured.filter.FilterContext;
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.specification.FilterableRequestSpecification;
|
||||
import io.restassured.specification.FilterableResponseSpecification;
|
||||
|
||||
import org.springframework.restdocs.config.SnippetConfigurer;
|
||||
|
||||
/**
|
||||
* A configurer that can be used to configure the generated documentation snippets when
|
||||
* using REST Assured.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public final class RestAssuredSnippetConfigurer extends
|
||||
SnippetConfigurer<RestAssuredRestDocumentationConfigurer, RestAssuredSnippetConfigurer> implements Filter {
|
||||
|
||||
RestAssuredSnippetConfigurer(RestAssuredRestDocumentationConfigurer parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec,
|
||||
FilterContext context) {
|
||||
return and().filter(requestSpec, responseSpec, context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.restassured.filter.Filter;
|
||||
import io.restassured.filter.FilterContext;
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.specification.FilterableRequestSpecification;
|
||||
import io.restassured.specification.FilterableResponseSpecification;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationContext;
|
||||
import org.springframework.restdocs.generate.RestDocumentationGenerator;
|
||||
import org.springframework.restdocs.snippet.Snippet;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A REST Assured {@link Filter} for documenting RESTful APIs.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class RestDocumentationFilter implements Filter {
|
||||
|
||||
static final String CONTEXT_KEY_CONFIGURATION = "org.springframework.restdocs.configuration";
|
||||
|
||||
private final RestDocumentationGenerator<FilterableRequestSpecification, Response> delegate;
|
||||
|
||||
RestDocumentationFilter(RestDocumentationGenerator<FilterableRequestSpecification, Response> delegate) {
|
||||
Assert.notNull(delegate, "delegate must be non-null");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Response filter(FilterableRequestSpecification requestSpec,
|
||||
FilterableResponseSpecification responseSpec, FilterContext context) {
|
||||
Response response = context.next(requestSpec, responseSpec);
|
||||
|
||||
Map<String, Object> configuration = getConfiguration(requestSpec, context);
|
||||
|
||||
this.delegate.handle(requestSpec, response, configuration);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration that should be used when calling the delgate. The
|
||||
* configuration is derived from the given {@code requestSpec} and {@code context}.
|
||||
* @param requestSpec the request specification
|
||||
* @param context the filter context
|
||||
* @return the configuration
|
||||
*/
|
||||
protected Map<String, Object> getConfiguration(FilterableRequestSpecification requestSpec, FilterContext context) {
|
||||
Map<String, Object> configuration = new HashMap<>(retrieveConfiguration(context));
|
||||
configuration.put(RestDocumentationContext.class.getName(),
|
||||
context.<RestDocumentationContext>getValue(RestDocumentationContext.class.getName()));
|
||||
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, requestSpec.getUserDefinedPath());
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link RestDocumentationFilter} that will produce documentation using
|
||||
* the given {@code snippets}.
|
||||
* @param snippets the snippets
|
||||
* @return the new result handler
|
||||
*/
|
||||
public final RestDocumentationFilter document(Snippet... snippets) {
|
||||
return new RestDocumentationFilter(this.delegate.withSnippets(snippets)) {
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getConfiguration(FilterableRequestSpecification requestSpec,
|
||||
FilterContext context) {
|
||||
Map<String, Object> configuration = super.getConfiguration(requestSpec, context);
|
||||
configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS);
|
||||
configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR);
|
||||
configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private static Map<String, Object> retrieveConfiguration(FilterContext context) {
|
||||
Map<String, Object> configuration = context.getValue(CONTEXT_KEY_CONFIGURATION);
|
||||
Assert.state(configuration != null,
|
||||
() -> "REST Docs configuration not found. Did you forget to add a "
|
||||
+ RestAssuredRestDocumentationConfigurer.class.getSimpleName()
|
||||
+ " as a filter when building the RequestSpecification?");
|
||||
return configuration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core classes for using Spring REST Docs with REST Assured.
|
||||
*/
|
||||
package org.springframework.restdocs.restassured;
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.specification.FilterableRequestSpecification;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
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.operation.RequestCookie;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestAssuredRequestConverter}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class RestAssuredRequestConverterTests {
|
||||
|
||||
@ClassRule
|
||||
public static TomcatServer tomcat = new TomcatServer();
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final RestAssuredRequestConverter factory = new RestAssuredRequestConverter();
|
||||
|
||||
@Test
|
||||
public void requestUri() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort());
|
||||
requestSpec.get("/foo/bar");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getUri()).isEqualTo(URI.create("http://localhost:" + tomcat.getPort() + "/foo/bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestMethod() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort());
|
||||
requestSpec.head("/foo/bar");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getMethod()).isEqualTo(HttpMethod.HEAD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryStringParameters() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).queryParam("foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters()).hasSize(1);
|
||||
assertThat(request.getParameters()).containsEntry("foo", Collections.singletonList("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryStringFromUrlParameters() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort());
|
||||
requestSpec.get("/?foo=bar&foo=qix");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters()).hasSize(1);
|
||||
assertThat(request.getParameters()).containsEntry("foo", Arrays.asList("bar", "qix"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formParameters() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).formParam("foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters()).hasSize(1);
|
||||
assertThat(request.getParameters()).containsEntry("foo", Collections.singletonList("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestParameters() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).param("foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParameters()).hasSize(1);
|
||||
assertThat(request.getParameters()).containsEntry("foo", Collections.singletonList("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headers() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).header("Foo", "bar");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getHeaders()).hasSize(2);
|
||||
assertThat(request.getHeaders()).containsEntry("Foo", Collections.singletonList("bar"));
|
||||
assertThat(request.getHeaders()).containsEntry("Host",
|
||||
Collections.singletonList("localhost:" + tomcat.getPort()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWithCustomAccept() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).header("Foo", "bar")
|
||||
.accept("application/json");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getHeaders()).hasSize(3);
|
||||
assertThat(request.getHeaders()).containsEntry("Foo", Collections.singletonList("bar"));
|
||||
assertThat(request.getHeaders()).containsEntry("Accept", Collections.singletonList("application/json"));
|
||||
assertThat(request.getHeaders()).containsEntry("Host",
|
||||
Collections.singletonList("localhost:" + tomcat.getPort()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cookies() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).cookie("cookie1", "cookieVal1")
|
||||
.cookie("cookie2", "cookieVal2");
|
||||
requestSpec.get("/");
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getCookies().size()).isEqualTo(2);
|
||||
|
||||
Iterator<RequestCookie> cookieIterator = request.getCookies().iterator();
|
||||
RequestCookie cookie1 = cookieIterator.next();
|
||||
|
||||
assertThat(cookie1.getName()).isEqualTo("cookie1");
|
||||
assertThat(cookie1.getValue()).isEqualTo("cookieVal1");
|
||||
|
||||
RequestCookie cookie2 = cookieIterator.next();
|
||||
assertThat(cookie2.getName()).isEqualTo("cookie2");
|
||||
assertThat(cookie2.getValue()).isEqualTo("cookieVal2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipart() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort())
|
||||
.multiPart("a", "a.txt", "alpha", null).multiPart("b", new ObjectBody("bar"), "application/json");
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
Collection<OperationRequestPart> parts = request.getParts();
|
||||
assertThat(parts).hasSize(2);
|
||||
assertThat(parts).extracting("name").containsExactly("a", "b");
|
||||
assertThat(parts).extracting("submittedFileName").containsExactly("a.txt", "file");
|
||||
assertThat(parts).extracting("contentAsString").containsExactly("alpha", "{\"foo\":\"bar\"}");
|
||||
assertThat(parts).extracting("headers").extracting(HttpHeaders.CONTENT_TYPE).containsExactly(
|
||||
Collections.singletonList(MediaType.TEXT_PLAIN_VALUE),
|
||||
Collections.singletonList(MediaType.APPLICATION_JSON_VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byteArrayBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().body("body".getBytes()).port(tomcat.getPort());
|
||||
requestSpec.post();
|
||||
this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().body("body").port(tomcat.getPort());
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getContentAsString()).isEqualTo("body");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void objectBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().body(new ObjectBody("bar")).port(tomcat.getPort());
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getContentAsString()).isEqualTo("{\"foo\":\"bar\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byteArrayInputStreamBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().body(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }))
|
||||
.port(tomcat.getPort());
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getContent()).isEqualTo(new byte[] { 1, 2, 3, 4 });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().body(new File("src/test/resources/body.txt"))
|
||||
.port(tomcat.getPort());
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getContentAsString()).isEqualTo("file");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileInputStreamBody() throws FileNotFoundException {
|
||||
FileInputStream inputStream = new FileInputStream("src/test/resources/body.txt");
|
||||
RequestSpecification requestSpec = RestAssured.given().body(inputStream).port(tomcat.getPort());
|
||||
requestSpec.post();
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Cannot read content from input stream " + inputStream + " due to reset() failure");
|
||||
this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartWithByteArrayInputStreamBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("foo", "foo.txt",
|
||||
new ByteArrayInputStream("foo".getBytes()));
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartWithStringBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("control", "foo");
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartWithByteArrayBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("control", "file",
|
||||
"foo".getBytes());
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartWithFileBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort())
|
||||
.multiPart(new File("src/test/resources/body.txt"));
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("file");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartWithFileInputStreamBody() throws FileNotFoundException {
|
||||
FileInputStream inputStream = new FileInputStream("src/test/resources/body.txt");
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("foo", "foo.txt",
|
||||
inputStream);
|
||||
requestSpec.post();
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Cannot read content from input stream " + inputStream + " due to reset() failure");
|
||||
this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartWithObjectBody() {
|
||||
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("control",
|
||||
new ObjectBody("bar"));
|
||||
requestSpec.post();
|
||||
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
|
||||
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("{\"foo\":\"bar\"}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample object body to verify JSON serialization.
|
||||
*/
|
||||
public static class ObjectBody {
|
||||
|
||||
private final String foo;
|
||||
|
||||
ObjectBody(String foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
public String getFoo() {
|
||||
return this.foo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import io.restassured.http.Headers;
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.response.ResponseBody;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.restdocs.operation.OperationResponse;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestAssuredResponseConverter}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class RestAssuredResponseConverterTests {
|
||||
|
||||
private final RestAssuredResponseConverter converter = new RestAssuredResponseConverter();
|
||||
|
||||
@Test
|
||||
public void responseWithCustomStatus() {
|
||||
Response response = mock(Response.class);
|
||||
given(response.getStatusCode()).willReturn(600);
|
||||
given(response.getHeaders()).willReturn(new Headers());
|
||||
ResponseBody<?> body = mock(ResponseBody.class);
|
||||
given(response.getBody()).willReturn(body);
|
||||
given(body.asByteArray()).willReturn(new byte[0]);
|
||||
OperationResponse operationResponse = this.converter.convert(response);
|
||||
assertThat(operationResponse.getStatus()).isNull();
|
||||
assertThat(operationResponse.getStatusCode()).isEqualTo(600);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.restassured.filter.FilterContext;
|
||||
import io.restassured.specification.FilterableRequestSpecification;
|
||||
import io.restassured.specification.FilterableResponseSpecification;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.restdocs.generate.RestDocumentationGenerator;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.Preprocessors;
|
||||
import org.springframework.restdocs.snippet.WriterResolver;
|
||||
import org.springframework.restdocs.templates.TemplateEngine;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestAssuredRestDocumentationConfigurer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class RestAssuredRestDocumentationConfigurerTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
private final FilterableRequestSpecification requestSpec = mock(FilterableRequestSpecification.class);
|
||||
|
||||
private final FilterableResponseSpecification responseSpec = mock(FilterableResponseSpecification.class);
|
||||
|
||||
private final FilterContext filterContext = mock(FilterContext.class);
|
||||
|
||||
private final RestAssuredRestDocumentationConfigurer configurer = new RestAssuredRestDocumentationConfigurer(
|
||||
this.restDocumentation);
|
||||
|
||||
@Test
|
||||
public void nextFilterIsCalled() {
|
||||
this.configurer.filter(this.requestSpec, this.responseSpec, this.filterContext);
|
||||
verify(this.filterContext).next(this.requestSpec, this.responseSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationIsAddedToTheContext() {
|
||||
this.configurer.operationPreprocessors().withRequestDefaults(Preprocessors.prettyPrint())
|
||||
.withResponseDefaults(Preprocessors.removeHeaders("Foo"))
|
||||
.filter(this.requestSpec, this.responseSpec, this.filterContext);
|
||||
@SuppressWarnings("rawtypes")
|
||||
ArgumentCaptor<Map> configurationCaptor = ArgumentCaptor.forClass(Map.class);
|
||||
verify(this.filterContext).setValue(eq(RestDocumentationFilter.CONTEXT_KEY_CONFIGURATION),
|
||||
configurationCaptor.capture());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> configuration = configurationCaptor.getValue();
|
||||
assertThat(configuration.get(TemplateEngine.class.getName())).isInstanceOf(TemplateEngine.class);
|
||||
assertThat(configuration.get(WriterResolver.class.getName())).isInstanceOf(WriterResolver.class);
|
||||
assertThat(configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS))
|
||||
.isInstanceOf(List.class);
|
||||
assertThat(configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR))
|
||||
.isInstanceOf(OperationRequestPreprocessor.class);
|
||||
assertThat(configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR))
|
||||
.isInstanceOf(OperationResponsePreprocessor.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright 2014-2022 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.restdocs.templates.TemplateFormat;
|
||||
import org.springframework.restdocs.templates.TemplateFormats;
|
||||
import org.springframework.restdocs.testfixtures.SnippetConditions;
|
||||
import org.springframework.restdocs.testfixtures.SnippetConditions.CodeBlockCondition;
|
||||
import org.springframework.restdocs.testfixtures.SnippetConditions.HttpRequestCondition;
|
||||
import org.springframework.restdocs.testfixtures.SnippetConditions.HttpResponseCondition;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
|
||||
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.maskLinks;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
|
||||
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.payload.PayloadDocumentation.subsectionWithPath;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParts;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
|
||||
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
|
||||
|
||||
/**
|
||||
* Integration tests for using Spring REST Docs with REST Assured.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Tomasz Kopczynski
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class RestAssuredRestDocumentationIntegrationTests {
|
||||
|
||||
@Rule
|
||||
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@ClassRule
|
||||
public static TomcatServer tomcat = new TomcatServer();
|
||||
|
||||
@Test
|
||||
public void defaultSnippetGeneration() {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("default")).get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/default"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void curlSnippetWithContent() throws Exception {
|
||||
String contentType = "text/plain; charset=UTF-8";
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("curl-snippet-with-content")).accept("application/json").body("content")
|
||||
.contentType(contentType).post("/").then().statusCode(200);
|
||||
|
||||
assertThat(new File("build/generated-snippets/curl-snippet-with-content/curl-request.adoc")).has(content(
|
||||
codeBlock(TemplateFormats.asciidoctor(), "bash").withContent(String.format("$ curl 'http://localhost:"
|
||||
+ tomcat.getPort() + "/' -i -X POST \\%n" + " -H 'Accept: application/json' \\%n"
|
||||
+ " -H 'Content-Type: " + contentType + "' \\%n" + " -d 'content'"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void curlSnippetWithCookies() throws Exception {
|
||||
String contentType = "text/plain; charset=UTF-8";
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("curl-snippet-with-cookies")).accept("application/json").contentType(contentType)
|
||||
.cookie("cookieName", "cookieVal").get("/").then().statusCode(200);
|
||||
assertThat(new File("build/generated-snippets/curl-snippet-with-cookies/curl-request.adoc")).has(content(
|
||||
codeBlock(TemplateFormats.asciidoctor(), "bash").withContent(String.format("$ curl 'http://localhost:"
|
||||
+ tomcat.getPort() + "/' -i -X GET \\%n" + " -H 'Accept: application/json' \\%n"
|
||||
+ " -H 'Content-Type: " + contentType + "' \\%n" + " --cookie 'cookieName=cookieVal'"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void curlSnippetWithEmptyParameterQueryString() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("curl-snippet-with-empty-parameter-query-string")).accept("application/json")
|
||||
.param("a", "").get("/").then().statusCode(200);
|
||||
assertThat(
|
||||
new File("build/generated-snippets/curl-snippet-with-empty-parameter-query-string/curl-request.adoc"))
|
||||
.has(content(codeBlock(TemplateFormats.asciidoctor(), "bash")
|
||||
.withContent(String.format("$ curl 'http://localhost:" + tomcat.getPort()
|
||||
+ "/?a=' -i -X GET \\%n -H 'Accept: application/json'"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void curlSnippetWithQueryStringOnPost() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("curl-snippet-with-query-string")).accept("application/json").param("foo", "bar")
|
||||
.param("a", "alpha").post("/?foo=bar").then().statusCode(200);
|
||||
String contentType = "application/x-www-form-urlencoded; charset=ISO-8859-1";
|
||||
assertThat(new File("build/generated-snippets/curl-snippet-with-query-string/curl-request.adoc"))
|
||||
.has(content(codeBlock(TemplateFormats.asciidoctor(), "bash")
|
||||
.withContent(String.format("$ curl " + "'http://localhost:" + tomcat.getPort()
|
||||
+ "/?foo=bar' -i -X POST \\%n" + " -H 'Accept: application/json' \\%n"
|
||||
+ " -H 'Content-Type: " + contentType + "' \\%n" + " -d 'a=alpha'"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linksSnippet() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("links", links(linkWithRel("rel").description("The description"))))
|
||||
.accept("application/json").get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc", "links.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathParametersSnippet() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("path-parameters",
|
||||
pathParameters(parameterWithName("foo").description("The description"))))
|
||||
.accept("application/json").get("/{foo}", "").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/path-parameters"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc", "path-parameters.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestParametersSnippet() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("request-parameters",
|
||||
requestParameters(parameterWithName("foo").description("The description"))))
|
||||
.accept("application/json").param("foo", "bar").get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/request-parameters"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc", "request-parameters.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestFieldsSnippet() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("request-fields", requestFields(fieldWithPath("a").description("The description"))))
|
||||
.accept("application/json").body("{\"a\":\"alpha\"}").post("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/request-fields"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc", "request-fields.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestPartsSnippet() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("request-parts", requestParts(partWithName("a").description("The description"))))
|
||||
.multiPart("a", "foo").post("/upload").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/request-parts"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc", "request-parts.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseFieldsSnippet() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("response-fields",
|
||||
responseFields(fieldWithPath("a").description("The description"),
|
||||
subsectionWithPath("links").description("Links to other resources"))))
|
||||
.accept("application/json").get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/response-fields"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc", "response-fields.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterizedOutputDirectory() throws Exception {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("{method-name}")).get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/parameterized-output-directory"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiStep() throws Exception {
|
||||
RequestSpecification spec = new RequestSpecBuilder().setPort(tomcat.getPort())
|
||||
.addFilter(documentationConfiguration(this.restDocumentation))
|
||||
.addFilter(document("{method-name}-{step}")).build();
|
||||
given(spec).get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/multi-step-1/"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
given(spec).get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/multi-step-2/"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
given(spec).get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/multi-step-3/"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void additionalSnippets() throws Exception {
|
||||
RestDocumentationFilter documentation = document("{method-name}-{step}");
|
||||
RequestSpecification spec = new RequestSpecBuilder().setPort(tomcat.getPort())
|
||||
.addFilter(documentationConfiguration(this.restDocumentation)).addFilter(documentation).build();
|
||||
given(spec).filter(documentation.document(
|
||||
responseHeaders(headerWithName("a").description("one"), headerWithName("Foo").description("two"))))
|
||||
.get("/").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/additional-snippets-1/"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc", "response-headers.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithCookie() {
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("set-cookie",
|
||||
preprocessResponse(removeHeaders(HttpHeaders.DATE, HttpHeaders.CONTENT_TYPE))))
|
||||
.get("/set-cookie").then().statusCode(200);
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/set-cookie"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
assertThat(new File("build/generated-snippets/set-cookie/http-response.adoc"))
|
||||
.has(content(httpResponse(TemplateFormats.asciidoctor(), HttpStatus.OK)
|
||||
.header(HttpHeaders.SET_COOKIE, "name=value; Domain=localhost; HttpOnly")
|
||||
.header("Keep-Alive", "timeout=60").header("Connection", "keep-alive")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preprocessedRequest() throws Exception {
|
||||
Pattern pattern = Pattern.compile("(\"alpha\")");
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation)).header("a", "alpha")
|
||||
.header("b", "bravo").contentType("application/json").accept("application/json")
|
||||
.body("{\"a\":\"alpha\"}").filter(document("original-request"))
|
||||
.filter(document("preprocessed-request",
|
||||
preprocessRequest(prettyPrint(), replacePattern(pattern, "\"<<beta>>\""),
|
||||
modifyUris().removePort(), removeHeaders("a", HttpHeaders.CONTENT_LENGTH))))
|
||||
.get("/").then().statusCode(200);
|
||||
assertThat(new File("build/generated-snippets/original-request/http-request.adoc"))
|
||||
.has(content(httpRequest(TemplateFormats.asciidoctor(), RequestMethod.GET, "/").header("a", "alpha")
|
||||
.header("b", "bravo").header("Accept", MediaType.APPLICATION_JSON_VALUE)
|
||||
.header("Content-Type", "application/json").header("Host", "localhost:" + tomcat.getPort())
|
||||
.header("Content-Length", "13").content("{\"a\":\"alpha\"}")));
|
||||
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\"%n}");
|
||||
assertThat(new File("build/generated-snippets/preprocessed-request/http-request.adoc"))
|
||||
.has(content(httpRequest(TemplateFormats.asciidoctor(), RequestMethod.GET, "/").header("b", "bravo")
|
||||
.header("Accept", MediaType.APPLICATION_JSON_VALUE).header("Content-Type", "application/json")
|
||||
.header("Host", "localhost").content(prettyPrinted)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPreprocessedRequest() throws Exception {
|
||||
Pattern pattern = Pattern.compile("(\"alpha\")");
|
||||
given().port(tomcat.getPort())
|
||||
.filter(documentationConfiguration(this.restDocumentation).operationPreprocessors().withRequestDefaults(
|
||||
prettyPrint(), replacePattern(pattern, "\"<<beta>>\""), modifyUris().removePort(),
|
||||
removeHeaders("a", HttpHeaders.CONTENT_LENGTH)))
|
||||
.header("a", "alpha").header("b", "bravo").contentType("application/json").accept("application/json")
|
||||
.body("{\"a\":\"alpha\"}").filter(document("default-preprocessed-request")).get("/").then()
|
||||
.statusCode(200);
|
||||
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\"%n}");
|
||||
assertThat(new File("build/generated-snippets/default-preprocessed-request/http-request.adoc"))
|
||||
.has(content(httpRequest(TemplateFormats.asciidoctor(), RequestMethod.GET, "/").header("b", "bravo")
|
||||
.header("Accept", MediaType.APPLICATION_JSON_VALUE).header("Content-Type", "application/json")
|
||||
.header("Host", "localhost").content(prettyPrinted)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preprocessedResponse() throws Exception {
|
||||
Pattern pattern = Pattern.compile("(\"alpha\")");
|
||||
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("original-response"))
|
||||
.filter(document("preprocessed-response",
|
||||
preprocessResponse(prettyPrint(), maskLinks(),
|
||||
removeHeaders("a", "Transfer-Encoding", "Date", "Server"),
|
||||
replacePattern(pattern, "\"<<beta>>\""),
|
||||
modifyUris().scheme("https").host("api.example.com").removePort())))
|
||||
.get("/").then().statusCode(200);
|
||||
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\",%n \"links\" : "
|
||||
+ "[ {%n \"rel\" : \"rel\",%n \"href\" : \"...\"%n } ]%n}");
|
||||
assertThat(new File("build/generated-snippets/preprocessed-response/http-response.adoc"))
|
||||
.has(content(httpResponse(TemplateFormats.asciidoctor(), HttpStatus.OK)
|
||||
.header("Foo", "https://api.example.com/foo/bar")
|
||||
.header("Content-Type", "application/json;charset=UTF-8").header("Keep-Alive", "timeout=60")
|
||||
.header("Connection", "keep-alive")
|
||||
.header(HttpHeaders.CONTENT_LENGTH, prettyPrinted.getBytes().length).content(prettyPrinted)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultPreprocessedResponse() throws Exception {
|
||||
Pattern pattern = Pattern.compile("(\"alpha\")");
|
||||
given().port(tomcat.getPort())
|
||||
.filter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
|
||||
.withResponseDefaults(prettyPrint(), maskLinks(),
|
||||
removeHeaders("a", "Transfer-Encoding", "Date", "Server"),
|
||||
replacePattern(pattern, "\"<<beta>>\""),
|
||||
modifyUris().scheme("https").host("api.example.com").removePort()))
|
||||
.filter(document("default-preprocessed-response")).get("/").then().statusCode(200);
|
||||
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\",%n \"links\" : "
|
||||
+ "[ {%n \"rel\" : \"rel\",%n \"href\" : \"...\"%n } ]%n}");
|
||||
assertThat(new File("build/generated-snippets/default-preprocessed-response/http-response.adoc"))
|
||||
.has(content(httpResponse(TemplateFormats.asciidoctor(), HttpStatus.OK)
|
||||
.header("Foo", "https://api.example.com/foo/bar")
|
||||
.header("Content-Type", "application/json;charset=UTF-8").header("Keep-Alive", "timeout=60")
|
||||
.header("Connection", "keep-alive")
|
||||
.header(HttpHeaders.CONTENT_LENGTH, prettyPrinted.getBytes().length).content(prettyPrinted)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customSnippetTemplate() throws Exception {
|
||||
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 {
|
||||
given().port(tomcat.getPort()).accept("application/json")
|
||||
.filter(documentationConfiguration(this.restDocumentation))
|
||||
.filter(document("custom-snippet-template")).get("/").then().statusCode(200);
|
||||
}
|
||||
finally {
|
||||
Thread.currentThread().setContextClassLoader(previous);
|
||||
}
|
||||
assertThat(new File("build/generated-snippets/custom-snippet-template/curl-request.adoc"))
|
||||
.hasContent("Custom curl request");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionShouldBeThrownWhenCallDocumentRequestSpecificationNotConfigured() {
|
||||
assertThatThrownBy(() -> given().port(tomcat.getPort()).filter(document("default")).get("/"))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("REST Docs configuration not found. Did you forget to add a "
|
||||
+ "RestAssuredRestDocumentationConfigurer as a filter when building the RequestSpecification?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionShouldBeThrownWhenCallDocumentSnippetsRequestSpecificationNotConfigured() {
|
||||
RestDocumentationFilter documentation = document("{method-name}-{step}");
|
||||
assertThatThrownBy(() -> given().port(tomcat.getPort())
|
||||
.filter(documentation.document(responseHeaders(headerWithName("a").description("one")))).get("/"))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("REST Docs configuration not found. Did you forget to add a "
|
||||
+ "RestAssuredRestDocumentationConfigurer as a filter when building the "
|
||||
+ "RequestSpecification?");
|
||||
}
|
||||
|
||||
private void assertExpectedSnippetFilesExist(File directory, String... snippets) {
|
||||
for (String snippet : snippets) {
|
||||
assertThat(new File(directory, snippet)).isFile();
|
||||
}
|
||||
}
|
||||
|
||||
private Condition<File> content(final Condition<String> delegate) {
|
||||
return new Condition<File>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(File value) {
|
||||
try {
|
||||
return delegate.matches(FileCopyUtils
|
||||
.copyToString(new InputStreamReader(new FileInputStream(value), StandardCharsets.UTF_8)));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
fail("Failed to read '" + value + "'", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private CodeBlockCondition<?> codeBlock(TemplateFormat format, String language) {
|
||||
return SnippetConditions.codeBlock(format, language);
|
||||
}
|
||||
|
||||
private HttpRequestCondition httpRequest(TemplateFormat format, RequestMethod requestMethod, String uri) {
|
||||
return SnippetConditions.httpRequest(format, requestMethod, uri);
|
||||
}
|
||||
|
||||
private HttpResponseCondition httpResponse(TemplateFormat format, HttpStatus status) {
|
||||
return SnippetConditions.httpResponse(format, status);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2014-20212the 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
|
||||
*
|
||||
* https://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.restassured;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.junit.rules.ExternalResource;
|
||||
|
||||
/**
|
||||
* {@link ExternalResource} that starts and stops a Tomcat server.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class TomcatServer extends ExternalResource {
|
||||
|
||||
private Tomcat tomcat;
|
||||
|
||||
private int port;
|
||||
|
||||
@Override
|
||||
protected void before() throws LifecycleException {
|
||||
this.tomcat = new Tomcat();
|
||||
this.tomcat.getConnector().setPort(0);
|
||||
Context context = this.tomcat.addContext("/", null);
|
||||
this.tomcat.addServlet("/", "test", new TestServlet());
|
||||
context.addServletMappingDecoded("/", "test");
|
||||
this.tomcat.addServlet("/", "set-cookie", new CookiesServlet());
|
||||
context.addServletMappingDecoded("/set-cookie", "set-cookie");
|
||||
this.tomcat.start();
|
||||
this.port = this.tomcat.getConnector().getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
try {
|
||||
this.tomcat.stop();
|
||||
}
|
||||
catch (LifecycleException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link HttpServlet} used to handle requests in the tests.
|
||||
*/
|
||||
private static final class TestServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
respondWithJson(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
respondWithJson(response);
|
||||
}
|
||||
|
||||
private void respondWithJson(HttpServletResponse response) throws IOException, JsonProcessingException {
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("application/json");
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
content.put("a", "alpha");
|
||||
Map<String, String> link = new HashMap<>();
|
||||
link.put("rel", "rel");
|
||||
link.put("href", "href");
|
||||
content.put("links", Arrays.asList(link));
|
||||
response.getWriter().println(new ObjectMapper().writeValueAsString(content));
|
||||
response.setHeader("a", "alpha");
|
||||
response.setHeader("Foo", "http://localhost:12345/foo/bar");
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link HttpServlet} used to handle cookies-related requests in the tests.
|
||||
*/
|
||||
private static final class CookiesServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
Cookie cookie = new Cookie("name", "value");
|
||||
cookie.setDomain("localhost");
|
||||
cookie.setHttpOnly(true);
|
||||
|
||||
resp.addCookie(cookie);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
1
spring-restdocs-restassured/src/test/resources/body.txt
Normal file
1
spring-restdocs-restassured/src/test/resources/body.txt
Normal file
@@ -0,0 +1 @@
|
||||
file
|
||||
@@ -0,0 +1 @@
|
||||
Custom curl request
|
||||
Reference in New Issue
Block a user