1

This question has already been asked in 2009 ( JUnit test for System.out.println() ). There are two "main" solutions:

  1. Using ByteArrayOutputStream().
  2. Using System Rules (3rd party) .

After reading System Rules API, it looks easier and more friendly to use.

The problem is, after a quick search online, it doesn't seem very popular.

What is the most accepted approach to do JUnit test for System.out in 2017?

GhostCat
  • 127,190
  • 21
  • 146
  • 218
Paz
  • 763
  • 2
  • 10
  • 26

1 Answers1

3

I think the 2017 answer should read like this:

  • you can use a ByteArrayOutputStream
  • you can use 3rd party libraries such as System Rules
  • you improve your design to avoid the need to do unit testing that relies on fetching content from System.out

Github shows that System Rules still seems "alive" (which is always a good sign when deciding if to use a 3rd party library) - and being around for 8 years implies that it is probably a mature product. So: when adding this external dependency is fine for you, just go for it.

But of course: the real answer still is: avoid writing such tests. There is nothing worse but hunting "bugs" because a legacy unit test fails all of a sudden - because some output message contains a space instead of a tab all for some stupid reason. Meaning: write code that emits Strings directly, and have unit tests check those.

Then have a single integration/function test that makes sure that your "plumbing" is correct, and that such "emitted" strings end up in System.out at some point.

Given the comment by the OP - which exactly underlines my point. The problem is code like this:

Scanner scanner = new Scanner(System.in);
if (scanner.next().equals("whatever")) {
  System.out.println("well"));
}

which has direct dependencies to System.in and System.out. So, in order to test the above code, one has somehow manipulate System.in and System.out therefore. Now look at this code:

 public class InOutExample {
   private final Scanner scanner;
   private final OutputStream out;

   public InOutExample() {
     this(new Scanner(), System.out);
   }
   /** unit test only */
   InOutExample(Scanner scanner, OutputStream out) {
     this.scanner = scanner;
     this.out = out;
   }

   public void foo() {
     if (scanner.next().equals("whatever")) {
       out.println("well"));
     }
   }

The above allows you to fully unit test your foo() method. Why? Because you can pass any scanner resp. out object into the example class that you want. You can either write your own stub implementation for the two objects, or you mock the objects and use the verification capabilities of your mocking framework to check that exactly the expected strings are sent to that special OutputStream out!

GhostCat
  • 127,190
  • 21
  • 146
  • 218
  • How thats work when I need constantly to "talk" with the user, i.e, the user has lot of decisions that he need to enter manualy as inputs (system.in), and the program should print out what to do next (system.out). I can call a function that get an input and print it, but I dont see the point. I think that I'm just not fully understand you. The first things that you write were really helpful – Paz Aug 01 '17 at 13:53