3

I'm trying to unit test a main method that takes input from the keyboard. I know there are several questions on SO about testing keyboard input and the use of System.setIn(...) to do so, but it only works for the first input for me.

My code:

public class TestApp {
    @Test
    public void testMain() {
        InputStream stdin = System.in;
        try {
            System.setIn(new ByteArrayInputStream("s\r\nx\r\n".getBytes()));

            String args[] = {};
            App.main(args);

            // TODO: verify that the output is what I expected it to be
        }
        catch(IOException e) {
            assertTrue("Unexpected exception thrown: " + e.getMessage(), false);
        }
        finally {
            System.setIn(stdin);
        }
    }
}

What I'm trying to achieve is to input 's' and then 'x' (two different entries).

When using the program normally, it should output stuff after pressing 's' followed by the enter key, and output something else after pressing 'x'. The main method looks like this:

class App {
    public static void main(String[] args) throws IOException {
        int choice;
        do {
            choice = getChar();
            switch(choice) {
                case 's':
                    System.out.println("Text for S");
                    break;
                case 'x':
                    System.out.println("Exiting");
                    break;
            }
        } while(choice != 'x');
    }

    public static String getString() throws IOException {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
        String s = br.readLine();
        return s;
    }

    public static char getChar() throws IOException {
        String s = getString();
        return s.charAt(0);
    }
}

Note: I know the best way to achieve it is to inject an InputStream dependency and use it instead of System.in, but I can't change the code. This is a restriction I have, I can't change main(), getString() or getChar() methods.

When I execute the test, this is the output:

Text for S

java.lang.NullPointerException
at App.getChar(tree.java:28)
at App.main(tree.java:7)
at TestApp.testMain(TestApp.java:15) <23 internal calls>

So, it looks like it gets the first input ('s'), but not the second one...

Any help greatly appreciated.

4
  • What's the point of unit testing some code if you can't even fix the bugs and design problems detected by the unit test? Commented Apr 6, 2013 at 10:57
  • It's an assignment, my task is to detect the defects and write a report about it. Fixing the bugs is not part of the assignment and I must not change the code... :( Commented Apr 6, 2013 at 11:07
  • 1
    So it seems you've found a defect: the code is not easily unit-testable. Commented Apr 6, 2013 at 11:08
  • Thanks, that's what I thought, but maybe someone knows a way to unit test it... Commented Apr 6, 2013 at 11:09

1 Answer 1

1

The getString method constructs a new BufferedReader on each call, which will read 8192 characters from System.in into its buffer before readLine returns. That means it's reading the 's' as well as the 'x' on the first call, but only using the first line. Then, on return from the method, the BufferedReader is discarded. On the next call it constructs a new instance to look for remaining characters but, as System.in is already drained, finds none.

It goes without saying that that's a bug.

One possible workaround would be to construct a dummy InputStream, with padding up to the 8k mark after the initial 's' and newline followed by the 'x' and newline.

You could also construct a more elaborate mock System.in coupled with a mock System.out and replenish it with more input when you detect a call to System.out.println.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.