Redirect console output to string in Java - java

I have one method whose return type is void and it prints directly on console.
However I need that output in a String so that I can work on it.
As I can't make any changes to the method with return type void I have to redirect that output to a String.
How can I redirect it in Java?

If the function is printing to System.out, you can capture that output by using the System.setOut method to change System.out to go to a PrintStream provided by you. If you create a PrintStream connected to a ByteArrayOutputStream, then you can capture the output as a String.
Example:
// 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());
This program prints just one line:
Here: Foofoofoo!

Here is a utility Class named ConsoleOutputCapturer. It allows the output to go to the existing console however behind the scene keeps capturing the output text. You can control what to capture with the start/stop methods. In other words call start to start capturing the console output and once you are done capturing you can call the stop method which returns a String value holding the console output for the time window between start-stop calls. This class is not thread-safe though.
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();
}
}
}
}

Although this question is very old and has already very good answers I want to provide an alternative. I created a library specifically for this use case. It is called Console Captor and you can add it with the following snippet:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>consolecaptor</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
Example class
public class FooService {
public void sayHello() {
System.out.println("Keyboard not responding. Press any key to continue...");
System.err.println("Congratulations, you are pregnant!");
}
}
Unit test
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();
}
}

If you are using Spring Framework, there is a really easy way to do this with 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");
}
}

Related

How can I get my text to not print one character per line?

I have this code which pulls the source code from the website listed. When the text is printed out each letter is in a different line. I need the line setup to be the same as the source code on chrome. How could I get it to print out like that?
package downloader;
import java.io.*;
import java.util.*;
import java.net.*;
public class Scannerup {
public static void main(String args[]) throws IOException
{
URL obj = new URL("https://www.papajohns.com/");
URLConnection con = obj.openConnection();
InputStream in1 = con.getInputStream();
int i;
do {
i = in1.read();
if(i!=-1)
{
System.out.println((char)i);
}
}
while(i!=-1);
}
}
Notice this
if(i!=-1)
{
System.out.println((char)i); ----------> You are using println
}
Change it to
if(i!=-1)
{
System.out.print((char)i);
}
print() - will print the required output on the same line again and again. (This is what you should of used)
println() - will print the output in the next line(This is what you use in your code)

Unable to print in Bluej console using PrintWriter

Consider the following code-
import java.io.*;
public class test
{
public static void main(String[] args)
{
PrintWriter out= new PrintWriter(System.out);
out.println(1);
out.close();
}
}
I run it on bluej for the first time and get output 1 on console. On running it again i get no output at all and same is the case for any subsequent tries.
Would love to know why this is happening.
Ok, the problem why this method only works once is, that the PrintWriter.close() method also closes the parent Stream, in this case System.out.
So when you call this method the next time, System.out will be closed, and nothing will be printed.
So the solution is not to close the PrintWriter.
But in this case, nothing is printed, because the output of the PrintWriter is not flushed. To do that, you either have to call out.flush() yourself or use a constructor which enables auto-flushing on line-endings.
tl;dr:
Either use this:
import java.io.*;
public class test
{
public static void main(String[] args)
{
PrintWriter out= new PrintWriter(System.out);
out.println(1);
out.flush();
}
}
or this:
import java.io.*;
public class test
{
public static void main(String[] args)
{
PrintWriter out= new PrintWriter(System.out, true);
out.println(1);
}
}

Find the location in code of a system.out.println

Lets say I'm working in a very large project, and have noticed an empty print line, so I'm assuming there is a System.out.println(""); located somewhere in the code. How would I go about trying to figure out where it is, short of just searching the entire project for all occurrences of System.out.println?
If you're using Java 8+, Durian has a StackDumper class which makes it easy to find where a given line is being printed:
StackDumper.dumpWhenSysOutContains("SomeTrigger")
When "SomeTrigger" is printed, this will get dumped to System.err:
+----------\
| Triggered by SomeTrigger
| at package.MyClass.myMethod(MyClass.java:62)
| (the rest of the stacktrace)
+----------/
For your case (looking for an empty string), it's a little more complicated:
PrintStream sysOutClean = System.out;
StringPrinter sysOutReplacement = new StringPrinter(StringPrinter.stringsToLines(line -> {
if (line.isEmpty()) {
StackDumper.dump("Found empty line");
}
sysOutClean.println(line);
}));
System.setOut(sysOutReplacement.toPrintStream());
Now if there's something like this:
System.out.println("ABC");
System.out.println("123");
System.out.println("");
System.out.println("DEF");
Then your console will look like this:
ABC
123
+----------\
| Found empty line
| at package.MyClass.myMethod(MyClass.java:62)
| (the rest of the stacktrace)
+----------/
DEF
You could implement your own PrintStream and use System.setOut to replace the default stdout. Then either put a debugging marker inside the class (if an empty string is printed), or print out the method name through the call stack (throw and catch an exception and get the stack information).
Example:
/** Control sysout prints */
public static void main(String[] arg) throws Exception {
System.out.println("Default"); //print normally
SysOutController.setSysOutLocationAddressor();
System.out.println("With Address"); //prints with calling location, and on click location cursor directly focus when System.out.**() called
SysOutController.ignoreSysout();
System.out.println("Ignored"); //this line will never prints
SysOutController.resetSysOut();
System.out.println("Default"); //print normally as it is (reset)
}
Just call methods of following class, which helps developers to controll sysout
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
/**
* Class which controls System.out prints in console <br/>
* this class will helps developers to control prints in console
* #implSpec
* <pre><code>
* System.out.println("Default"); //print normally
*
* SysOutController.setSysOutLocationAddressor();
* System.out.println("With Address"); //prints with calling location
*
* SysOutController.ignoreSysout();
* System.out.println("Ignored"); //this line will never prints
*
* SysOutController.resetSysOut();
* System.out.println("Default"); //print normally as it is (reset)
* </code></pre>
* #author Dharmendrasinh Chudasama
*/
public class SysOutController {
private static void setOut(OutputStream out){
System.setOut(new PrintStream(out));
}
private static final OutputStream CONSOLE = new FileOutputStream(FileDescriptor.out);
/**
* Reset System.out.print* method
* #author Dharmendrasinh Chudasama
*/
public static void resetSysOut() { setOut(CONSOLE); }
/**
* System.out.print* will not print anything in console
* #author Dharmendrasinh Chudasama
*/
public static void ignoreSysout() {
setOut(new OutputStream() {
#Override public void write(int b) throws IOException {}
});
}
/**
* Address/location of calling System.out.* method will append in console
* #author Dharmendrasinh Chudasama
*/
public static void setSysOutLocationAddressor() {
setOut(new OutputStream() {
#Override
public void write(int b) throws IOException {
if(b=='\n'){ //if newLine
final StackTraceElement callerStEl = new Throwable().getStackTrace()[9];
String pathData =
"\u001B[37m" //low-visibality
+ "\t :: ("+callerStEl.getFileName()+":"+callerStEl.getLineNumber()+") ["+callerStEl+"]" //code path
+ "\u001B[0m "; //reset
CONSOLE.write(pathData.getBytes());
}
CONSOLE.write(b);
}
});
}
}
This can be due to some of the library also,if you feel that it is because of only System.out.println then,
Solution 1 :
Below code snippet should help you to find out the place where it is getting executed.
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class CustomPrintStream extends PrintStream {
public CustomPrintStream(String fileName) throws FileNotFoundException {
super(fileName);
}
#Override
public void print(String s) {
try{
if(s == null || s.equals("")){
throw new Exception("Invalid print message");
}
super.print(s);
}catch(Exception e){
//TODO Change to your logger framework and leave it as same
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
//TODO : Change to your favorite path and make sure mentioned
//file is available
CustomPrintStream customPrintStream = new CustomPrintStream
("/home/prem/Desktop/test.log");
System.setOut(customPrintStream);
System.out.println("");
} catch (FileNotFoundException e) {
//TODO Change to your logger framework and leave it as same
e.printStackTrace();
}
}
}
Solution 2 :
Since IDE's are available,please get the help from them.If you are using eclipse
Menu -> Search - > File Search-> Place System.out.println(""); in containing search and search for it.
I would rather say not to use the System.out.println in any of the code,for which you can make use of checkstyle and be confident that hence forth no developers use them.
Define a class NewPrintStream extends PrintStream
import java.io.FileNotFoundException;
import java.io.PrintStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NewPrintStream extends PrintStream {
private static final Logger LOGGER = LoggerFactory.getLogger(NewPrintStream.class);
public NewPrintStream(String fileName) throws FileNotFoundException {
super(fileName);
}
#Override
public void println(String x) {
LOGGER.info("xxxxxxx", new Exception("xxxx"));
}
}
Then in main class set stdout/stderr print stream
System.setOut(new NewPrintStream("aaa"));
System.setErr(new NewPrintStream("aaa"));
Put a conditional breakpoint in PrintStream.println(String x) with the condition set to x.equals("") or whatever your string may be.

Java - System.setOut does not save an exception message

It seems that System.setOut() does not work in this test case.
Here are problem description.
test0 executes System.setOut(new PrintStream(byteBuffer)) so that it stores standard output.
test0 invokes AddChild1_wy_v1.main.
In the AddChild1_wy_v1.main, xml.addChild(null) generates an exception message.
The exception message should be stored in byteBuffer, but it seems it wasn't.. JVM stops running the test case once the exception message pops up. And the remaining code after AddChild1_wy_v1.main are not executed.
Is there a way for jvm to execute the remaining code in test0?
NanoAddChild1_wy_v1Tests.java
package tests;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import net.n3.nanoxml.*;
public class NanoAddChild1_wy_v1Tests extends TestCase {
public void test0() throws Exception { //addchild1.out
String result;
ByteArrayOutputStream byteBuffer;
byteBuffer = new ByteArrayOutputStream();
System.setOut(new PrintStream(byteBuffer));
AddChild1_wy_v1.main(new String[] {"/home/junghyun/Dev/nanoxml/inputs/simple.xml"});
result = new String(byteBuffer.toByteArray());
assertEquals(result, "Exception in thread \"main\" java.lang.IllegalArgumentException: child must not be null\n\tat net.n3.nanoxml.XMLElement.addChild(XMLElement.java:165)\n\tat AddChild1_wy_v1.main(AddChild1_wy_v1.java:47)\n");
}
}
AddChild1_wy_v1.java
package tests;
import net.n3.nanoxml.IXMLParser;
import net.n3.nanoxml.IXMLReader;
import net.n3.nanoxml.StdXMLReader;
import net.n3.nanoxml.XMLElement;
import net.n3.nanoxml.XMLParserFactory;
import net.n3.nanoxml.XMLWriter;
public class AddChild1_wy_v1
{
public static void main(String args[])
throws Exception
{
if (args.length == 0) {
System.err.println("Usage: java DumpXML file.xml");
Runtime.getRuntime().exit(1);
}
IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
IXMLReader reader = StdXMLReader.fileReader(args[0]);
parser.setReader(reader);
XMLElement xml = (XMLElement) parser.parse();
xml.addChild (null);
(new XMLWriter(System.out)).write(xml);
}
}
There's 3 default streams:
System.in : InputStream
System.out :PrintStream
System.err :PrintStream
So to set each one there is 3 methods:
public static void setIn(InputStream in) {...}
public static void setOut(PrintStream out) {...}
public static void setErr(PrintStream err) {...}
To set System.err you must use System.setErr(yourStream);
For another question: you just need to use
try {
//throwing exception
} catch (Exception e) {
//act on exception
}
It seems to me that you never write that Exception at all.
You just throw it upwards. Try catch it and have ex.printStackTrace();
Also that will go to standard error, unless you specifically say otherwise.
As by your request I will leave the test0 method unaltered, you can use it the way it is.
in AddChild1_wy_v1.java:
public class AddChild1_wy_v1 {
public static void main(String args[]) // note that I don't throw the Exception.
{
try {
if (args.length == 0) {
System.err.println("Usage: java DumpXML file.xml");
Runtime.getRuntime().exit(1);
}
IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
IXMLReader reader = StdXMLReader.fileReader(args[0]);
parser.setReader(reader);
XMLElement xml = (XMLElement) parser.parse();
xml.addChild (null);
(new XMLWriter(System.out)).write(xml);
} catch (Exception any) {
any.printStackTrace(System.out); // note that I send the Stack Trace to standard out here.
}
}
}
Wrap your method call in a try-catch to continue past the exception:
try {
AddChild1_wy_v1.main(...);
} catch(Throwable t) {
t.printStackTrace();
}
// the rest of your code will execute
Exceptions are printed to standard error, not standard output. Try System.setErr.
Never post images of your code.

Testing outputstream.write(<String>) without creating a file

I am testing a output stream in java something like below.
Writer outputStream = getOutputStream(fileName);
if(outputStream != null) {
try {
outputStream.write(inputText);
}
finally {
outputStream.close();
}
}
else {
throw new IOException("Output stream is null");
}
I am write a mockito test as below
public void testFileWrite() throws IOException {
when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(outputStreamMock);
doNothing().when(outputStreamMock).write(Matchers.anyString());
doNothing().when(bufferedReaderMock).close();
testObj.write(outputFileNameValidValue, reveredFileInput);
verify(outputStreamMock).write(Matchers.anyString());
verify(outputStreamMock).close();
}
The problem is when you create OutputStreamWriter(new FileOutputStream(filename)) a physical file on the disk is created.
Can we test Outputstream.write without actually writing a file on the disk?
Thanks
Anand
You can use ByteArrayOutputStream which writes the data in memory. You can read this with a ByteArrayInputStream.
An alternative is to write an expecting OutputStream which fails as soon as you attempt to write an incorrect byte. This can be helpful to see exactly where/why a test fails.
You could try using System.out for your output which is actually a Printstream, which is a subclass of OutputStream
see:
http://docs.oracle.com/javase/6/docs/api/java/lang/System.html
http://docs.oracle.com/javase/6/docs/api/java/io/PrintStream.html
As other suggested already you need to be able to inject a mocked OutputStream in your class under test. As your class under test needs a OutputStream which writes into a given file, you will need to inject a mockable OutputStreamFactory into your class under test.
I have this code for you which is fully self contained:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.io.IOException;
import java.io.OutputStream;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class Test9328173 {
private ClassUnderTest testObj;
#Mock
private OutputStreamFactory factory;
#Mock
private OutputStream stream;
#Before
public void setUp() throws Exception {
testObj = new ClassUnderTest();
testObj.factory = factory;
}
#Test
public void testFileWrite() throws Exception {
when(factory.create("filename")).thenReturn(stream);
testObj.write("filename", new byte[]{1, 2, 3});
verify(stream).write(new byte[]{1, 2, 3});
verify(stream).close();
}
private class ClassUnderTest {
private OutputStreamFactory factory;
public void write(String filename, byte[] content) throws IOException {
OutputStream stream = factory.create(filename);
try {
stream.write(content);
} finally {
stream.close();
}
}
}
private interface OutputStreamFactory {
OutputStream create(String filename);
}
}
You should mock up your getOutputStream: is should return mocked output stream object. Invocation of new FileOutputStream indeed creates file on disk.
Theoretically you can mock up file system itself but it is much more complicated.
And BTW if(outputStream != null) is redundant: stream can never be null. If it cannot be created the method should throw exception. It is not C, it is Java. :)
You should have the mocked getOutputStream(String) return a java.io.StringWriter and you can then assert that the expected content was written.
public void testFileWrite() throws IOException {
StringWriter writer = new StringWriter();
when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(writer);
testObj.write(outputFileNameValidValue, reveredFileInput);
assertEquals(reveredFileInput, writer.toString());
verify(writer).close();
}

Categories

Resources