【发布时间】:2012-02-01 06:15:52
【问题描述】:
我有一种方法,它的返回类型是void,它直接在控制台上打印。
但是我需要在字符串中输出该输出,以便我可以处理它。
由于我无法对返回类型为 void 的方法进行任何更改,因此我必须将该输出重定向到字符串。
如何在 Java 中重定向它?
【问题讨论】:
标签: java string redirect console stdout
我有一种方法,它的返回类型是void,它直接在控制台上打印。
但是我需要在字符串中输出该输出,以便我可以处理它。
由于我无法对返回类型为 void 的方法进行任何更改,因此我必须将该输出重定向到字符串。
如何在 Java 中重定向它?
【问题讨论】:
标签: java string redirect console stdout
如果您使用的是 Spring Framework,那么使用 OutputCaptureExtension 可以很简单地做到这一点:
@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");
}
}
【讨论】:
虽然这个问题已经很老了,并且已经有了很好的答案,但我想提供一个替代方案。我专门为这个用例创建了一个库。它被称为Console Captor,您可以使用以下 sn-p 添加它:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>consolecaptor</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
示例类
public class FooService {
public void sayHello() {
System.out.println("Keyboard not responding. Press any key to continue...");
System.err.println("Congratulations, you are pregnant!");
}
}
单元测试
import static org.assertj.core.api.Assertions.assertThat;
import nl.altindag.console.ConsoleCaptor;
import org.junit.jupiter.api.Test;
public class FooServiceTest {
@Test
public void captureStandardAndErrorOutput() {
ConsoleCaptor consoleCaptor = new ConsoleCaptor();
FooService fooService = new FooService();
fooService.sayHello();
assertThat(consoleCaptor.getStandardOutput()).contains("Keyboard not responding. Press any key to continue...");
assertThat(consoleCaptor.getErrorOutput()).contains("Congratulations, you are pregnant!");
consoleCaptor.close();
}
}
【讨论】:
如果函数打印到System.out,您可以通过使用System.setOut 方法将System.out 更改为您提供的PrintStream 来捕获该输出。如果您创建一个连接到ByteArrayOutputStream 的PrintStream,那么您可以将输出捕获为String。
例子:
// Create a stream to hold the output
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
// IMPORTANT: Save the old System.out!
PrintStream old = System.out;
// Tell Java to use your special stream
System.setOut(ps);
// Print some output: goes to your special stream
System.out.println("Foofoofoo!");
// Put things back
System.out.flush();
System.setOut(old);
// Show what happened
System.out.println("Here: " + baos.toString());
这个程序只打印一行:
Here: Foofoofoo!
【讨论】:
baos.toString() 很容易成为 "Foofohello worldofoo!"
这是一个名为 ConsoleOutputCapturer 的实用程序类。它允许输出到现有的控制台,但在幕后不断捕获输出文本。您可以使用 start/stop 方法控制要捕获的内容。换句话说,调用 start 开始捕获控制台输出,一旦完成捕获,您可以调用 stop 方法,该方法返回一个 String 值,用于保存 start-stop 调用之间的时间窗口的控制台输出。不过这个类不是线程安全的。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
public class ConsoleOutputCapturer {
private ByteArrayOutputStream baos;
private PrintStream previous;
private boolean capturing;
public void start() {
if (capturing) {
return;
}
capturing = true;
previous = System.out;
baos = new ByteArrayOutputStream();
OutputStream outputStreamCombiner =
new OutputStreamCombiner(Arrays.asList(previous, baos));
PrintStream custom = new PrintStream(outputStreamCombiner);
System.setOut(custom);
}
public String stop() {
if (!capturing) {
return "";
}
System.setOut(previous);
String capturedValue = baos.toString();
baos = null;
previous = null;
capturing = false;
return capturedValue;
}
private static class OutputStreamCombiner extends OutputStream {
private List<OutputStream> outputStreams;
public OutputStreamCombiner(List<OutputStream> outputStreams) {
this.outputStreams = outputStreams;
}
public void write(int b) throws IOException {
for (OutputStream os : outputStreams) {
os.write(b);
}
}
public void flush() throws IOException {
for (OutputStream os : outputStreams) {
os.flush();
}
}
public void close() throws IOException {
for (OutputStream os : outputStreams) {
os.close();
}
}
}
}
【讨论】: