0

Im trying to make a test in JUnit where I want to test if the console prints out the message I want it to print. The code looks like this:

public class MainTestingClass extends TestCase {

    private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();

    @Before
    public void setUpStreams() {
        System.setOut(new PrintStream(outContent));
    }

    @After
    public void cleanUpStreams() {
        System.setOut(null);
    }

    @Test
    public void testPracticalViewConsole() {
        PracticalView view = new PracticalView();
        view.PrintResults();
        assertEquals("welcome to the macro counting app", outContent.toString());
    }
}

but for some reason the system.out still prints to the console and in the test i get:

junit.framework.ComparisonFailure: Expected :welcome to the macro counting app Actual :

And I have no idea what the problem is.

beresfordt
  • 5,088
  • 10
  • 35
  • 43
  • What are you trying to test here? You assertion asserts that `outContent` defined in your setup is equal to something. You are not testing `PracticalView` at all. – Jaroslaw Pawlak Nov 17 '15 at 13:42
  • Trying to test if the class Practical view prints out "welcome to the macro counting app" in the console. – Jakob Brandt Nov 17 '15 at 13:43
  • outContent should (according to my understanding) get the output stream of System.out calls, such as the one called in the method from PracticalView. IE the outContent variable should be assigned whatever is printed in the method I'm trying to test. – Jakob Brandt Nov 17 '15 at 13:46
  • I'd guess, the output is still buffered in the `PrintStream` because it was not closed. – Henry Nov 17 '15 at 13:46

2 Answers2

3

Interacting with System class is quite ugly solution, not to mention that System.setOut(null) may have possible side effects (e.g. you won't be able to see anything more in the console in this JVM). I am not sure how it works exactly, because the method is native while its javadoc is vague.

A good practice in testing is to isolate your code from the code you don't control (here System class). You should wrap System.out.println into your own class:

public class Printer {

    public void println(Object object) {
        System.out.println(object);
    }

}

Then you can use a mocking framework (here: mockito) to mock Printer, do dependency injection and assert on interactions:

@Test
public void testPracticalViewConsole(){
    Printer printer = mock(Printer.class);
    PracticalView view = new PracticalView(printer);

    view.PrintResults();

    verify(printer, times(1)).println("welcome to the macro counting app");
}

EDIT:

To help you getting started with mockito, here is a single maven dependency you need:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.10.19</version>
</dependency>

And these are the imports for the test above:

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Jaroslaw Pawlak
  • 5,538
  • 7
  • 30
  • 57
  • 2
    `System.setOut(null);` will almost certainly fail. +1 – Peter Lawrey Nov 17 '15 at 13:47
  • the solution that im following atm is this http://stackoverflow.com/questions/1119385/junit-test-for-system-out-println, and the reason for that is because i dont know how to use mocking – Jakob Brandt Nov 17 '15 at 13:54
  • 1
    @JakobBrandt There is no testing without mocking, so you should learn it. I recommend mockito (this is what I used here). It's quite simple and verbose, you don't need a lot of extra setup as when using jmock. – Jaroslaw Pawlak Nov 17 '15 at 13:55
  • Thanks. I used the answer below for this specific test, but I will be using Mocking for the upcoming tests in this project as it appears to be indeed very good. Thanks a lot for the help! – Jakob Brandt Nov 17 '15 at 14:57
3

I've reproduced your experiment, and I've found empirically that the cause of this weird behaviour is the superclass TestCase (which is not even necessary, since you're using JUNIT 4 annotations). Drop it off and see how it works fine.

And, although is not strictly necessary, it will be safer if you instantiate the PrintStream with autoFlush=true:

System.setOut(new PrintStream(outContent, true));
Little Santi
  • 8,563
  • 2
  • 18
  • 46
  • 1
    The main problem is extending `TestCase` which is JUnIt 3 and then using annotations `@Before` and `@After` which are JUnit 4. TestCase does not know about annotations. If you have to use TestCase rename your Before and After methods `setUp()` and `tearDown()` – dkatzel Nov 17 '15 at 14:47