Add support for manually managing the RestDocumentationContext

In 1.0, the reliance on JUnit was more widespread than it should have
been. It should have been isolated to the JUnit TestRule implementation,
RestDocumentation. Unfortunately, RestDocumentation was also an argument
to MockMvcRestDocumentation.documentationConfiguration which made it
impossible to use Spring REST Docs without having JUnit on the
classpath.

This commit introduces JUnitRestDocumentation and
ManualRestDocumentation. The format is a direct replacement for
RestDocumentation which has been reworked to delegate to
JUnitRestDocumentation. The latter allows manual management of the
RestDocumentationContext, primarily for use with TestNG.

A new interface, RestDocumentationContextProvider, has been introduced.
It is implemented by RestDocumentation, JUnitRestDocumentation and
ManualRestDocumentation.
MockMvcRestDocumentation.documentationConfiguration has been overridden
to also accept a RestDocumentationContextProvider. The method that
accepts a RestDocumentation has been deprecated, as has
RestDocumentation itself.

The documentation has been updated to encourage the use of
JUnitRestDocumentation and a sample illustrating the use of Spring REST
Docs with TestNG has been added.

Closes gh-171
This commit is contained in:
Andy Wilkinson
2016-02-08 15:22:15 +00:00
parent 6578f42730
commit 0ef9307481
46 changed files with 932 additions and 108 deletions

View File

@@ -203,7 +203,7 @@ from where it will be included in the jar file.
[[getting-started-documentation-snippets]]
=== Generating documentation snippets
Spring REST Docs uses JUnit and
Spring REST Docs uses
{spring-framework-docs}/#spring-mvc-test-framework[Spring's MVC Test framework] or
http://www.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
@@ -214,11 +214,18 @@ response.
[[getting-started-documentation-snippets-setup]]
==== Setting up your tests
The first step in generating documentation snippets is to declare a `public`
`RestDocumentation` field that's annotated as a JUnit `@Rule`. The `RestDocumentation`
rule is configured with the output directory into which generated snippets should be
written. This output directory should match the snippets directory that you have
configured in your `build.gradle` or `pom.xml` file.
Exactly how you setup your tests depends on the test framework that you're using.
Spring REST Docs provides first-class support for JUnit. Other frameworks, such as TestNG,
are also supported although slightly more setup is required.
[[getting-started-documentation-snippets-setup-junit]]
===== Setting up your JUnit tests
When using JUnit, the first step in generating documentation snippets is to declare a
`public` `JUnitRestDocumentation` field that's annotated as a JUnit `@Rule`. The
`JUnitRestDocumentation` rule is configured with the output directory into which generated
snippets should be written. This output directory should match the snippets directory that
you have configured in your `build.gradle` or `pom.xml` file.
For Maven (`pom.xml` that will typically be `target/generated-snippets` and for
Gradle (`build.gradle`) it will typically be `build/generated-snippets`:
@@ -227,14 +234,16 @@ Gradle (`build.gradle`) it will typically be `build/generated-snippets`:
.Maven
----
@Rule
public RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");
public JUnitRestDocumentation restDocumentation =
new JUnitRestDocumentation("target/generated-snippets");
----
[source,java,indent=0,role="secondary"]
.Gradle
----
@Rule
public RestDocumentation restDocumentation = new RestDocumentation("build/generated-snippets");
public JUnitRestDocumentation restDocumentation =
new JUnitRestDocumentation("build/generated-snippets");
----
Next, provide an `@Before` method to configure MockMvc or REST Assured:
@@ -263,6 +272,54 @@ configuration. Refer to the <<configuration, configuration section>> for more in
===== Setting up your tests without JUnit
[[getting-started-documentation-snippets-setup-manual]]
The configuration when JUnit is not being used is largely similar to when it is being
used. This section describes the key differences. The {samples}/testng[TestNG sample] also
illustrates the approach.
The first difference is that `ManualRestDocumentation` should be used in place of
`JUnitRestDocumentation` and there's no need for the `@Rule` annotation:
[source,java,indent=0,role="primary"]
.Maven
----
private ManualRestDocumentation restDocumentation =
new ManualRestDocumentation("target/generated-snippets");
----
[source,java,indent=0,role="secondary"]
.Gradle
----
private ManualRestDocumentation restDocumentation =
new ManualRestDocumentation("build/generated-snippets");
----
Secondly, `ManualRestDocumentation.beforeTest(Class, String)`
must be called before each test. This can be done as part of the method that is
configuring MockMVC or REST Assured:
[source,java,indent=0,role="primary"]
.MockMvc
----
include::{examples-dir}/com/example/mockmvc/ExampleApplicationTestNgTests.java[tags=setup]
----
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/ExampleApplicationTestNgTests.java[tags=setup]
----
Lastly, `ManualRestDocumentation.afterTest` must be called after each test. For example,
with TestNG:
[source,java,indent=0]
----
include::{examples-dir}/com/example/restassured/ExampleApplicationTestNgTests.java[tags=teardown]
----
[[getting-started-documentation-snippets-invoking-the-service]]
==== Invoking the RESTful service

View File

@@ -16,21 +16,22 @@
package com.example.mockmvc;
import static org.springframework.restdocs.curl.CurlDocumentation.curlRequest;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.curl.CurlDocumentation.curlRequest;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
public class CustomDefaultSnippets {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
@Autowired
private WebApplicationContext context;

View File

@@ -16,20 +16,21 @@
package com.example.mockmvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
public class CustomEncoding {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
@Autowired
private WebApplicationContext context;

View File

@@ -16,21 +16,22 @@
package com.example.mockmvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.restdocs.templates.TemplateFormats;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
public class CustomFormat {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
@Autowired
private WebApplicationContext context;

View File

@@ -16,20 +16,21 @@
package com.example.mockmvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
public class CustomUriConfiguration {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
@Autowired
private WebApplicationContext context;

View File

@@ -18,6 +18,7 @@ package com.example.mockmvc;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
import org.springframework.test.web.servlet.MockMvc;
@@ -38,7 +39,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class EveryTestPreprocessing {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation(
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
"target/generated-snippets");
private WebApplicationContext context;

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.mockmvc;
import java.lang.reflect.Method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.restdocs.ManualRestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
public class ExampleApplicationTestNgTests {
public final ManualRestDocumentation restDocumentation = new ManualRestDocumentation(
"target/generated-snippets");
// tag::setup[]
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@BeforeMethod
public void setUp(Method method) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation))
.build();
this.restDocumentation.beforeTest(getClass(), method.getName());
}
// end::setup[]
// tag::teardown[]
@AfterMethod
public void tearDown() {
this.restDocumentation.afterTest();
}
// end::teardown[]
}

View File

@@ -19,7 +19,7 @@ package com.example.mockmvc;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@@ -29,7 +29,7 @@ import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.docu
public class ExampleApplicationTests {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation(
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
"target/generated-snippets");
// tag::setup[]
@Autowired
@@ -44,4 +44,5 @@ public class ExampleApplicationTests {
.build();
}
// end::setup[]
}

View File

@@ -18,6 +18,7 @@ package com.example.mockmvc;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@@ -29,7 +30,7 @@ import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.docu
public class ParameterizedOutput {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
private MockMvc mockMvc;

View File

@@ -32,7 +32,7 @@ import org.springframework.test.web.servlet.MockMvc;
public class Payload {
private MockMvc mockMvc;
private MockMvc mockMvc;
public void response() throws Exception {
// tag::response[]

View File

@@ -18,6 +18,7 @@ package com.example.restassured;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import com.jayway.restassured.builder.RequestSpecBuilder;
@@ -29,9 +30,9 @@ import static org.springframework.restdocs.restassured.RestAssuredRestDocumentat
public class CustomDefaultSnippets {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
RequestSpecification spec;
private RequestSpecification spec;
@Before
public void setUp() {

View File

@@ -18,6 +18,7 @@ package com.example.restassured;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import com.jayway.restassured.builder.RequestSpecBuilder;
@@ -28,7 +29,7 @@ import static org.springframework.restdocs.restassured.RestAssuredRestDocumentat
public class CustomEncoding {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
private RequestSpecification spec;

View File

@@ -18,6 +18,7 @@ package com.example.restassured;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.restdocs.templates.TemplateFormats;
@@ -29,7 +30,7 @@ import static org.springframework.restdocs.restassured.RestAssuredRestDocumentat
public class CustomFormat {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("build");
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build");
private RequestSpecification spec;

View File

@@ -18,6 +18,7 @@ package com.example.restassured;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.restdocs.restassured.RestDocumentationFilter;
@@ -38,7 +39,7 @@ import static org.springframework.restdocs.restassured.RestAssuredRestDocumentat
public class EveryTestPreprocessing {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation(
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
"target/generated-snippets");
// tag::setup[]

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.restassured;
import java.lang.reflect.Method;
import org.springframework.restdocs.ManualRestDocumentation;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.specification.RequestSpecification;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class ExampleApplicationTestNgTests {
private final ManualRestDocumentation restDocumentation = new ManualRestDocumentation(
"build/generated-snippets");
// 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[]
}

View File

@@ -18,6 +18,7 @@ package com.example.restassured;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import com.jayway.restassured.builder.RequestSpecBuilder;
@@ -28,7 +29,7 @@ import static org.springframework.restdocs.restassured.RestAssuredRestDocumentat
public class ExampleApplicationTests {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation(
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
"build/generated-snippets");
// tag::setup[]

View File

@@ -18,6 +18,7 @@ package com.example.restassured;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.RestDocumentation;
import com.jayway.restassured.builder.RequestSpecBuilder;
@@ -29,7 +30,7 @@ import static org.springframework.restdocs.restassured.RestAssuredRestDocumentat
public class ParameterizedOutput {
@Rule
public final RestDocumentation restDocumentation = new RestDocumentation(
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(
"build/generated-snippets");
private RequestSpecification spec;