4

I am writing a JUnit for a program created in an exercise. That means the test needs to cover as many cases as possible and I don't have any influence on how certain things in the program are implemented. Also, the program runs an infinite loop where at one point, it requires the user to input something.
For the JUnit test I run the program in another Thread and simulate the user input from within the JUnit Thread.

So far, everything works fine if the program reads the user input from System.in, because this stream can easily replaced. But there's also the possiblity that the program interacts with System.console() which currently can not be covered by my test.

Is there any possibility to simulate input for the System.console(), e.g. by replacing its input source with another stream?

(NB: The JUnit test must use Java 6 without any external libraries (except JUnit and Hamcrest).)

Edit: Unfortunately, I can't change the classes of the program to test.

  • Your class' constructor has to accept a `Console` object, so you can *inject* it. Then in the test you will have to construct a *mock* instance of `Console` which you'll have to pass to the constructor. – Svetlin Zarev Apr 03 '15 at 14:28
  • @SvetlinZarev see my edit. Is there no other way? – darktestuser Apr 03 '15 at 15:21

3 Answers3

5

After looking at the JDK source code I found the the Console class is reading data from the standard input (System.in):

reader = new LineReader(StreamDecoder.forInputStreamReader(new FileInputStream(FileDescriptor.in), readLock, cs));

Where FileDescriptor.in is a constant pointing to the real standard input (public static final FileDescriptor in = standardStream(0);). So even if you substitute System.in using System.setIn() the console class will still use the real standard input.

Your only option is to substitute the Console object with a mock.

Svetlin Zarev
  • 14,713
  • 4
  • 53
  • 82
3

I think you need to create an abstraction for the console as explained in this post. And use this abstraction in the code instead of System.console(). Then you can mock the abstraction you control in the tests.

EDIT: Another solution which is more involved, is to modify the byte code of System.console() (or sun underlying classes) when it is loaded in the JVM. This is done by providing your own implementation of a ClassLoader and you can find information on how to do that. I'm not sure you want to go this rabbit hole...

T.Gounelle
  • 5,953
  • 1
  • 22
  • 32
  • Since I cannot influence what the actual program uses as console, the abstraction would be useless because the program would still use `System.console()` and not my custom console. This would be different, if you could change the console used, like it is possible with `System.in` using `System.setIn()` – darktestuser Apr 03 '15 at 12:11
0

On way i can think of use of mocking scanner class. For example

     int i = sc.nextInt(); 

now mock implementation will be called

 public void Scanner getScanner(){

   }


  // inject mock object for unit testing and in prod ,
      real object with input   stream from console
   public void Scanner setScanner(Scanner scanner){

    }
M Sach
  • 33,416
  • 76
  • 221
  • 314