0
votes

This post is similar to: this

I have a console app that expects both user input and has responsive user output. I am writing some unit tests for it to make sure that the code works properly. I need to be able to make sure that the output and input for it are what I expect them to be.

Essentially, I have a main method being tested that asks for a file or input. In my test, I use System.setOut and System.setIn to set those to context.mock versions of PrintStream and InputStream objects respectively. I don't care about what System.out.println calls get made until I have to test the actual processing of the program data, when it outputs its results to the console. So to summarize:

Here's my source being tested (something close, I trimmed much out): http://ideone.com/rptC0

Here's what I have in my mocking procedure: http://ideone.com/VkvqM

And here's the exception that I'm getting: ideone.com/OEOS8

As you can clearly see in my expectations, I'm explicitly saying that I was planning to print the exact same string out, and I specified that in my expectations. But the exception says that it was unexpected. I don't understand...

1
If you're going to post linked code, a SSCCE will probably get you better answers quicker...DNA
you're right, sorry, repost with SSCCE below.Adam Miller
Unfortunately, that's not self-contained (several other classes are needed such as Word and WordFrequency) nor correct - main doesn't compile because it uses type 'bool' and calls an undefined method inputReadFailureDNA
Oh crap... err. I wasn't finished editing the link when you took it. Hold on, I'll fix those, I just finished fixing them...Adam Miller
OK, I have edited my copy to get it working and I think I see the problem - see my comment below (will also edit the answer).DNA

1 Answers

0
votes

JMock expects you to declare the Expectations using context.checking() then call the code under test, then call context.assertIsSatisfied() (although sometimes the last step is done implicitly if using an appropriate test runner).

You seem to be immediately calling context.assertIsSatisfied() before running any code.

Also, the code you posted uses the variable mn which does not appear to be defined - is that actually the code you are running? Or should that variable be mockIn instead?

Updated: OK, the problem is probably that you are trying to mock a static method - JMock doesn't support this - see jmock mocking a static method . See particularly the answer from Steve Freeman, who is one of the JMock authors.

Updated 2: I would try something like this, setting an expectation in the @Before setup:

@Before
public void setMinimalMockingExpectations() throws IOException
{
    oldIn = System.in;
    oldOut = System.out;
    pipe = new PipedOutputStream();
    testIn = new PipedInputStream(pipe);
    mockOut = context.mock(PrintStream.class);
    System.setOut(mockOut);
    System.setIn(testIn);

    expectQuestion();
}

private void expectQuestion()
{
    Expectations exp = new Expectations()
    {
        {
            one(mockOut).println(main.QUESTION);
        }
    };
    context.checking(exp);

}

@After
public void reset()
{
    System.setIn(oldIn);
    System.setOut(oldOut);
}

@Test
public void fileChoiceReturnsFalse() throws IOException
{
    String FILE = "F\n";
    pipe.write(FILE.getBytes());

    assertFalse(main.promptStringOrFile());

    context.assertIsSatisfied(); // can avoid this call by using the right
                                    // test runner
}

and create two similar tests to check behaviour for input "I" and any other input (for which the question should be repeated once).

The promptStringOrFile() method is probably clearer if you use BufferedReader.readLine() rather than worrying about chars.