JUnit test for System.out.println()
using ByteArrayOutputStream and System.setXXX is simple:
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();private final PrintStream originalOut = System.out;private final PrintStream originalErr = System.err;@Beforepublic void setUpStreams() { System.setOut(new PrintStream(outContent)); System.setErr(new PrintStream(errContent));}@Afterpublic void restoreStreams() { System.setOut(originalOut); System.setErr(originalErr);}
sample test cases:
@Testpublic void out() { System.out.print("hello"); assertEquals("hello", outContent.toString());}@Testpublic void err() { System.err.print("hello again"); assertEquals("hello again", errContent.toString());}
I used this code to test the command line option (asserting that -version outputs the version string, etc etc)
Edit:Prior versions of this answer called System.setOut(null)
after the tests; This is the cause of NullPointerExceptions commenters refer to.
I know this is an old thread, but there is a nice library to do this: System Rules
Example from the docs:
public void MyTest { @Rule public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); @Test public void overrideProperty() { System.out.print("hello world"); assertEquals("hello world", systemOutRule.getLog()); }}
It will also allow you to trap System.exit(-1)
and other things that a command line tool would need to be tested for.
Instead of redirecting System.out
, I would refactor the class that uses System.out.println()
by passing a PrintStream
as a collaborator and then using System.out
in production and a Test Spy in the test. That is, use Dependency Injection to eliminate the direct use of the standard output stream.
In Production
ConsoleWriter writer = new ConsoleWriter(System.out));
In the Test
ByteArrayOutputStream outSpy = new ByteArrayOutputStream();ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));writer.printSomething();assertThat(outSpy.toString(), is("expected output"));
Discussion
This way the class under test becomes testable by a simple refactoring, without having the need for indirect redirection of the standard output or obscure interception with a system rule.