Testing Console Output With JUnit and Infinitest
I saved the view components of my Tic-Tac-Toe game for last. The functionality I need to implement for a command line application is pretty simple: the view should be able to print game boards and messages to the terminal, prompt for user input and pass it off to a controller, and not much more. But doing this the TDD way was harder than I expected. Here are the solutions I found to two testing problems.
Testing text output
Printing a board should be a one-liner, especially since I added a
toString()
method to my Board
objects. System.out.println(Board)
ought to work just fine. But wait—the tests come first.
Writing tests against printed terminal output isn’t tough, but it does
require some setup. System.setOut()
redirects Java’s default output
to a byte stream of your choice.
First, save the default System.out
(It’s a PrintStream
), so you can switch back to stdout later.
Then, initialize a ByteArrayOutputStream
:
1 2 3 4 5 6 7 |
|
Add a setUp()
method with the JUnit @Before
annotation—the usual
pattern to run some code before your tests. Pass System.setOut()
a
UTF-8 PrintStream
object constructed with the byte array (You are
using UTF-8 everywhere, right?):
1 2 3 4 5 |
|
Then test against output
. If the terminal output is as expected, it
should match the result of the printed object’s toString()
method:
1 2 3 4 5 6 |
|
Finally, make sure you clean up and redirect output back to stdout, so later print statements don’t go missing:
1 2 3 4 5 |
|
Now you’re ready to write that one-liner. You can find the whole test class as a gist here.
Testing Unicode output with Infinitest
With my test in place, I wrote a quick print method and waited for the green flash. And waited. And waited… I’ve been using Infinitest, an excellent continuous testing plugin for IntelliJ and Eclipse, but it threw an assertion error, even though the tests passed when run directly from IntelliJ.
The problem? I wasn’t using Unicode
everywhere! (Don’t say I didn’t warn you.) My boards print with Unicode box
drawing characters that
threw off Infinitest. IntelliJ runs in a UTF-8 environment by default,
but character encoding must be passed as an option to the Infinitest
JVM. Fortunately, this is another one-line
solution:
add a text file named infinitest.args
in your project’s root directory with one argument per
line. In this case, just:
-D file.encoding=UTF-8
With tests back in the green, I was ready to start testing user input—but that’s a yak shave for another day.