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
    @RunWith(JUnit4.class)
    public class TerminalViewTest extends TicTacToeTest {

        private final PrintStream stdout = System.out;
        private final ByteArrayOutputStream output = new ByteArrayOutputStream();
        private TerminalView terminalview;

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
        @Before
        public void setUp() throws UnsupportedEncodingException {
            terminalview = new TerminalView();
            System.setOut(new PrintStream(output, true, "UTF-8"));
        }

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
        @Test
        public void terminalViewShouldPrintBoards() {
            terminalview.print(nowins);
            assertEquals(nowins.toString(), output.toString());

        }

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
        @After
        public void cleanUp() {
            System.setOut(stdout);
        }
    }

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.

Comments