diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/CapturedOutput.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/CapturedOutput.java index 22561e71d7..fa7e265371 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/CapturedOutput.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/CapturedOutput.java @@ -23,7 +23,7 @@ package org.springframework.boot.test.system; * standard JUnit assertions. For example:
* 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
*
*
* @author Madhura Bhave
diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/OutputCapture.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/OutputCapture.java
index 5fc6fd6ac4..d9a5b002e4 100644
--- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/OutputCapture.java
+++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/system/OutputCapture.java
@@ -38,6 +38,7 @@ import org.springframework.util.ClassUtils;
* @author Madhura Bhave
* @author Phillip Webb
* @author Andy Wilkinson
+ * @author Sam Brannen
* @see OutputCaptureExtension
* @see OutputCaptureRule
*/
@@ -125,7 +126,8 @@ class OutputCapture implements CapturedOutput {
}
private String get(Predicate- * 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: * *
* @ExtendWith(OutputCaptureExtension.class)
@@ -42,7 +44,15 @@ import org.junit.jupiter.api.extension.ParameterResolver;
*
* @Test
* void test(CapturedOutput output) {
+ * System.out.println("ok");
* assertThat(output).contains("ok");
+ * System.err.println("error");
+ * }
+ *
+ * @AfterEach
+ * void after(CapturedOutput output) {
+ * assertThat(output.getOut()).contains("ok");
+ * assertThat(output.getErr()).contains("error");
* }
*
* }
@@ -51,36 +61,35 @@ import org.junit.jupiter.api.extension.ParameterResolver;
* @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
@@ -90,9 +99,16 @@ public class OutputCaptureExtension
}
@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()));
}
}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCapture.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCapture.java
index 654a62e2cd..736bdc53ca 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCapture.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCapture.java
@@ -111,7 +111,8 @@ class OutputCapture implements CapturedOutput {
}
private String get(Predicate 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. Please check your output capture registration.");
StringBuilder builder = new StringBuilder();
for (SystemCapture systemCapture : this.systemCaptures) {
systemCapture.append(builder, filter);
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCaptureExtension.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCaptureExtension.java
index 2eed7f73c2..462eb4f9bd 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCaptureExtension.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCaptureExtension.java
@@ -20,47 +20,76 @@ import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
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;
/**
- * Internal JUnit 5 {@code @Extension} to capture {@link System#out System.out} and
- * {@link System#err System.err}.
+ * 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.
+ *
+ * To use with {@link ExtendWith @ExtendWith}, inject the {@link CapturedOutput} as an
+ * argument to your test class constructor, test method, or lifecycle methods:
+ *
+ *
+ * @ExtendWith(OutputCaptureExtension.class)
+ * class MyTest {
+ *
+ * @Test
+ * void test(CapturedOutput output) {
+ * System.out.println("ok");
+ * assertThat(output).contains("ok");
+ * System.err.println("error");
+ * }
+ *
+ * @AfterEach
+ * void after(CapturedOutput output) {
+ * assertThat(output.getOut()).contains("ok");
+ * assertThat(output.getErr()).contains("error");
+ * }
+ *
+ * }
+ *
*
* @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
@@ -70,9 +99,16 @@ public class OutputCaptureExtension
}
@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()));
}
}