Skip to content

Commit

Permalink
Polish OutputCapture and its JUnit Jupiter extension
Browse files Browse the repository at this point in the history
- Polish Javadoc
- Improve error message in OutputCapture
- Use ExtensionContext.Store in OutputCaptureExtension

See gh-17049
  • Loading branch information
sbrannen authored and wilkinsona committed Jul 18, 2019
1 parent b092cb7 commit e1c595a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* standard JUnit assertions. For example: <pre class="code">
* assertThat(output).contains("started"); // Checks all output
* assertThat(output.getErr()).contains("failed"); // Only checks System.err
* assertThat(output.getOut()).contains("ok"); // Only checks System.put
* assertThat(output.getOut()).contains("ok"); // Only checks System.out
* </pre>
*
* @author Madhura Bhave
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
* @author Madhura Bhave
* @author Phillip Webb
* @author Andy Wilkinson
* @author Sam Brannen
* @since 2.2.0
* @see OutputCaptureExtension
* @see OutputCaptureRule
*/
Expand Down Expand Up @@ -125,7 +127,12 @@ void reset() {
}

private String get(Predicate<Type> filter) {
Assert.state(!this.systemCaptures.isEmpty(), "No system captures found. Check that you have used @ExtendWith.");
Assert.state(!this.systemCaptures.isEmpty(),
"No system captures found. When using JUnit 4, ensure that you have "
+ "registered the OutputCaptureRule via @ClassRule or @Rule "
+ "and that the field is public. "
+ "When using JUnit Jupiter, ensure that you have registered "
+ "the OutputCaptureExtension via @ExtendWith.");
StringBuilder builder = new StringBuilder();
for (SystemCapture systemCapture : this.systemCaptures) {
systemCapture.append(builder, filter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,37 @@
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;

/**
* JUnit 5 {@code @Extension} to capture {@link System#out System.out} and
* {@link System#err System.err}. Can be used on a test class via
* {@link ExtendWith @ExtendWith}. This extension provides {@link ParameterResolver
* parameter resolution} for a {@link CapturedOutput} instance which can be used to assert
* that the correct output was written.
* JUnit Jupiter {@code @Extension} to capture {@link System#out System.out} and
* {@link System#err System.err}. Can be registered for an entire test class or for an
* individual test method via {@link ExtendWith @ExtendWith}. This extension provides
* {@linkplain ParameterResolver parameter resolution} for a {@link CapturedOutput}
* instance which can be used to assert that the correct output was written.
* <p>
* To use, add {@link ExtendWith @ExtendWith} and inject the {@link CapturedOutput} as an
* argument to your test class constructor or test method:
* To use with {@link ExtendWith @ExtendWith}, inject the {@link CapturedOutput} as an
* argument to your test class constructor, test method, or lifecycle methods:
*
* <pre class="code">
* &#064;ExtendWith(OutputCaptureExtension.class)
* class MyTest {
*
* &#064;Test
* void test(CapturedOutput output) {
* System.out.println("ok");
* assertThat(output).contains("ok");
* System.err.println("error");
* }
*
* &#064;AfterEach
* void after(CapturedOutput output) {
* assertThat(output.getOut()).contains("ok");
* assertThat(output.getErr()).contains("error");
* }
*
* }
Expand All @@ -51,36 +61,35 @@
* @author Madhura Bhave
* @author Phillip Webb
* @author Andy Wilkinson
* @author Sam Brannen
* @since 2.2.0
* @see CapturedOutput
*/
public class OutputCaptureExtension
implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, ParameterResolver {

private final OutputCapture outputCapture = new OutputCapture();

OutputCaptureExtension() {
// Package private to prevent users from directly creating an instance.
}

@Override
public void beforeAll(ExtensionContext context) throws Exception {
this.outputCapture.push();
getOutputCapture(context).push();
}

@Override
public void afterAll(ExtensionContext context) throws Exception {
this.outputCapture.pop();
getOutputCapture(context).pop();
}

@Override
public void beforeEach(ExtensionContext context) throws Exception {
this.outputCapture.push();
getOutputCapture(context).push();
}

@Override
public void afterEach(ExtensionContext context) throws Exception {
this.outputCapture.pop();
getOutputCapture(context).pop();
}

@Override
Expand All @@ -90,9 +99,16 @@ public boolean supportsParameter(ParameterContext parameterContext, ExtensionCon
}

@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return this.outputCapture;
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return getOutputCapture(extensionContext);
}

private OutputCapture getOutputCapture(ExtensionContext context) {
return getStore(context).getOrComputeIfAbsent(OutputCapture.class);
}

private Store getStore(ExtensionContext context) {
return context.getStore(Namespace.create(getClass()));
}

}

0 comments on commit e1c595a

Please sign in to comment.