Testing System.out.println in JUnit 5 Tests
In console applications, it may be handy to assert the result of a print statement. While much of your core logic can be tested without relying on this, sometimes you will need to test what the user sees. In the case of a console application that will be what is printed to the user.
Remember that JUnit tests run in their own environment. We can take advantage of this by controlling what System
holds during the JUnit session.
System.out
is really a ByteArrayOutputStream
object that the console writes to when a user types characters and hits enter. The problem is that by default, we don’t have access to check what was written to that stream. Fortunately, System.setOut
is a method available to set the outputstream that System
uses to our own.
By creating our own ByteArrayOutputStream
and setting System.out
to hold our stream, we can have direct access to check what was loaded into that stream for the entirety of the JUnit session.
Step 1: JUnit Setup
Make sure you have added JUnit as a dependency by following the steps here: JUnit Setup
Step 2: Set up objects
Create two final instance variables inside the JUnit test class. The ByteArrayOutputStream
will be passed to System.out
, and the PrintStream
will be used to later to reset System.out
to it’s default PrintStream
(to avoid interference for any tests that we do NOT want to intercept print statements).
private final PrintStream defaultOut = System.out;
private final ByteArrayOutputStream testOutputStream = new ByteArrayOutputStream();
Step 3: Set up BeforeEach and AfterEach methods
JUnit has nifty annotations you can use to automatically call a method of your choosing before every test. There is also an annotation to call a method after each test.
This method will set the System.out
for the JUnit session equal to our outputStream we created earlier. This is the key to being able to capture and see what gets written to the outputStream whenever a System.out.println
runs.
@BeforeEach
public void setOutputStream() {
System.setOut(new PrintStream(testOutputStream));
}
This part is only necessary to reduce interference with other tests, especially any tests where we DONT care to intecept the print results. It runs after each test, and resets System.out
back to the default, which we captured earlier in our instance variables.
@AfterEach
public void resetSystemOut() {
System.setOut(defaultOut);
}
Remember that both @BeforeEach
and @AfterEach
annotated methods will run at the appropriate times without having to be explicitly called.
Step 3: Use in a test
Now that the set up is done, you can assert for what was displayed in a System.out.println
statement by checking our copy of the testOutputStream
. It will be filled with whatever strings were written to System.out
when the test code was executed.
@Test
public void whenSomething_thenSomething() {
// ..... do test setup, perform an action ......
assertEquals("Expected string outputted to user", testOutputStream.toString().trim());
}
Note you can play around with the trim. It is to remove the newline character that appears when println
is used versus print
. You can also hardcode \n
inside your expected string to capture this or any new lines that appear inside your actual string.