Quickly validateSystem.out.println() output in JUnit by redirectingSystem.out to a ByteArrayOutputStream. Check the content with JUnit assertions. Let's dive into it:
import org.junit.Assert;
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
publicclassHelloWorldPrinterTest{
privatefinal ByteArrayOutputStream outContent = new ByteArrayOutputStream();
privatefinal PrintStream originalOut = System.out;
// This part is like setting the table before dinner ๐@BeforepublicvoidsetUpStreams(){
System.setOut(new PrintStream(outContent));
}
// Time to clean up! We had fun, didn't we? ๐@AfterpublicvoidrestoreStreams(){
System.setOut(originalOut);
}
@TestpublicvoidtestPrintln(){
System.out.println("Hello, World!");
Assert.assertEquals("Hello, World!\n", outContent.toString());
}
}
Grab the printed content with outContent.toString() and assert its correctness with Assert.assertEquals.
Extending the fast answer
Checking error output
You can testSystem.err output in the same way you did it for System.out. Just redirectSystem.err to a new ByteArrayOutputStream:
Just like we said ๐, what System.out can do, System.err can do too!
Testing System.exit() calls
If your application ends execution using System.exit(), you can test this by using the ExpectedSystemExit rule in the System Rules library:
import org.junit.Rule;
import org.junit.contrib.java.lang.system.ExpectedSystemExit;
publicclassApocalypseNowTest{
@Rulepublicfinal ExpectedSystemExit exit = ExpectedSystemExit.none();
@TestpublicvoidtestEndOfTheWorld(){
exit.expectSystemExitWithStatus(-1);
// Code that triggers the end of times (I mean, the call to System.exit(-1)) }
}
Brace yourself, Armageddon is coming! ๐
Making testing easier with Dependency Injection
You can inject a PrintStream for System.out into classes that write to the console, making mocking or replacement easier for testability:
@TestpublicvoidtestExecute(){
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
Command command = new Command(new PrintStream(outContent));
command.execute();
Assert.assertEquals("Executing command...\n", outContent.toString());
}
It's like giving your classes their own personal megaphone. ๐ข
More testing tips: Logging
Redirecting your output to a logging framework like Log4j or SLF4J can open doors to more elegant, granular testing:
Logger logger = LogManager.getLogger(MyClass.class);
ByteArrayOutputStream logContent = new ByteArrayOutputStream();
Appender mockAppender = createAppender("mockAppender", logContent); // Show-off time for Appenderlogger.addAppender(mockAppender);
// Trigger logging in your application// Assert log contentString logOutput = logContent.toString();
Assert.assertTrue("There's a glitch in the matrix, the message is lost! ๐ฑ", logOutput.contains("Expected message"));
Or, you can assert over the log messages with the help of ExpectedLogs
import org.apache.commons.testing.logging.ExpectedLogs;
import org.apache.logging.log4j.Level;
import org.junit.Rule;
publicclassLogMessageTest{
@Rulepublic ExpectedLogs logs = ExpectedLogs.none(MyClass.class);
@TestpublicvoidchecksLogMessage(){
logs.expect(Level.ERROR).toHaveMessageContaining("Something bad happened! ๐ง");
// Code that triggers the error log }
}
Hear that? That's the sweet sound of logs being tested. ๐ถ