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

@@ -0,0 +1,70 @@
/*
* 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 org.springframework.restdocs;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* A JUnit {@link TestRule} used to automatically manage the
* {@link RestDocumentationContext}.
*
* @author Andy Wilkinson
* @since 1.1.0
*/
public class JUnitRestDocumentation implements RestDocumentationContextProvider, TestRule {
private final ManualRestDocumentation delegate;
/**
* Creates a new {@code JUnitRestDocumentation} instance that will generate snippets
* to the given {@code outputDirectory}.
*
* @param outputDirectory the output directory
*/
public JUnitRestDocumentation(String outputDirectory) {
this.delegate = new ManualRestDocumentation(outputDirectory);
}
@Override
public Statement apply(final Statement base, final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Class<?> testClass = description.getTestClass();
String methodName = description.getMethodName();
JUnitRestDocumentation.this.delegate.beforeTest(testClass, methodName);
try {
base.evaluate();
}
finally {
JUnitRestDocumentation.this.delegate.afterTest();
}
}
};
}
@Override
public RestDocumentationContext beforeOperation() {
return this.delegate.beforeOperation();
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.restdocs;
import java.io.File;
/**
* {@code ManualRestDocumentation} is used to manually manage the
* {@link RestDocumentationContext}. Primarly intended for use with TestNG, but suitable
* for use in any environment where manual management of the context is required.
* <p>
* Users of JUnit should use {@link JUnitRestDocumentation} and take advantage of its
* Rule-based support for automatic management of the context.
*
* @author Andy Wilkinson
* @since 1.1.0
*/
public final class ManualRestDocumentation implements RestDocumentationContextProvider {
private final File outputDirectory;
private RestDocumentationContext context;
/**
* Creates a new {@code ManualRestDocumentation} instance that will generate snippets
* to the given {@code outputDirectory}.
*
* @param outputDirectory the output directory
*/
public ManualRestDocumentation(String outputDirectory) {
this.outputDirectory = new File(outputDirectory);
}
/**
* Notification that a test is about to begin. Creates a
* {@link RestDocumentationContext} for the test on the given {@code testClass} with
* the given {@code testMethodName}. Must be followed by a call to
* {@link #afterTest()} once the test has completed.
*
* @param testClass the test class
* @param testMethodName the name of the test method
* @throws IllegalStateException if a context has already be created
*/
@SuppressWarnings("deprecation")
public void beforeTest(Class<?> testClass, String testMethodName) {
if (this.context != null) {
throw new IllegalStateException(
"Context already exists. Did you forget to call afterTest()?");
}
this.context = new RestDocumentationContext(testClass, testMethodName,
this.outputDirectory);
}
/**
* Notification that a test has completed. Clears the {@link RestDocumentationContext}
* that was previously established by a call to {@link #beforeTest(Class, String)}.
*/
public void afterTest() {
this.context = null;
}
@Override
public RestDocumentationContext beforeOperation() {
this.context.getAndIncrementStepCount();
return this.context;
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.restdocs;
import java.io.File;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -27,13 +25,12 @@ import org.junit.runners.model.Statement;
* JUnit tests.
*
* @author Andy Wilkinson
*
* @deprecated Since 1.1 in favor of {@link JUnitRestDocumentation}
*/
public class RestDocumentation implements TestRule {
@Deprecated
public class RestDocumentation implements TestRule, RestDocumentationContextProvider {
private final String outputDirectory;
private RestDocumentationContext context;
private final JUnitRestDocumentation delegate;
/**
* Creates a new {@code RestDocumentation} instance that will generate snippets to the
@@ -42,40 +39,17 @@ public class RestDocumentation implements TestRule {
* @param outputDirectory the output directory
*/
public RestDocumentation(String outputDirectory) {
this.outputDirectory = outputDirectory;
this.delegate = new JUnitRestDocumentation(outputDirectory);
}
@Override
public Statement apply(final Statement base, final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Class<?> testClass = description.getTestClass();
String methodName = description.getMethodName();
RestDocumentation.this.context = new RestDocumentationContext(testClass,
methodName, new File(RestDocumentation.this.outputDirectory));
try {
base.evaluate();
}
finally {
RestDocumentation.this.context = null;
}
}
};
return this.delegate.apply(base, description);
}
/**
* Notification that a RESTful operation that should be documented is about to be
* performed. Returns a {@link RestDocumentationContext} for the operation.
*
* @return the context for the operation
*/
@Override
public RestDocumentationContext beforeOperation() {
this.context.getAndIncrementStepCount();
return this.context;
return this.delegate.beforeOperation();
}
}

View File

@@ -43,7 +43,9 @@ public final class RestDocumentationContext {
* @param testClass the class whose test is being executed
* @param testMethodName the name of the test method that is being executed
* @param outputDirectory the directory to which documentation should be written.
* @deprecated Since 1.1 in favor of {@link ManualRestDocumentation}.
*/
@Deprecated
public RestDocumentationContext(Class<?> testClass, String testMethodName,
File outputDirectory) {
this.testClass = testClass;

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.restdocs;
/**
* A {@code RestDocumentationContextProvider} is used to provide access to the
* {@link RestDocumentationContext}.
*
* @author Andy Wilkinson
* @since 1.1.0
*/
public interface RestDocumentationContextProvider {
/**
* Returns a {@link RestDocumentationContext} for the operation that is about to be
* performed.
*
* @return the context for the operation
*/
RestDocumentationContext beforeOperation();
}