Writing data to System.in
Asked Answered
B

4

14

In our application, we expect user input within a Thread as follows :

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

I want to pass that part in my unit test so that I can resume the thread to execute the rest of the code. How can I write something into System.in from junit?

Brechtel answered 28/9, 2010 at 14:55 Comment(6)
I didn't think you could, but apparently you can according to Justin. However, wouldn't it be better to refactor the tested code to get the inputstream inserted from outside?Graze
@Bart, if you are testing an app that takes input from System.in, eventually you will want to test the module that takes the data from System.in.Rubberneck
@Justin Isn't this testing Java and not your code? If you make the InputStream injected you are still testing all of your code and depending on Java to provide a correct System.in.Martens
@Justin: The two answers suggesting redirecting System.in are not really doing a complete job of that though, since System.in no longer reads from standard in which is what the application will be using. You're really not testing anything except for maybe whether the System class functions properly, which I assure you has been tested by Sun.Browbeat
@Jacob, no. You are testing how your code handles various inputs from System.in. You can automate the tests instead of having users enter in test data through a console.Rubberneck
@Mark, The application will be using the inputstream that System.in provides. The application shouldn't care where that data is coming from. When run in a production setting, it will be coming from a keyboard, but in the test, it will be coming from a text file, or some hard coded strings. You are testing the ability of your application to handle different types of inputs.Rubberneck
R
31

What you want to do is use the method setIn() from System. This will let you pass data into System.in from junit.

Rubberneck answered 28/9, 2010 at 14:58 Comment(2)
This works when I run the JUnit tests individually, but when I run the entire class my program seems to stall at the points where the setIn() should be working. Does anyone else have this issue, and if so any ideas on how to get around it?Hithermost
@Hithermost you problem may have been incorrect setup() & tearDown() modifying those values System.in() and System.out(). There are some other references to that problem elsewhere on SE. If anyone else sees this comment I'll search and replace..Indoiranian
J
11

Replace it for the duration of your test:

String data = "the text you want to send";
InputStream testInput = new ByteArrayInputStream( data.getBytes("UTF-8") );
InputStream old = System.in;
try {
    System.setIn( testInput );

    ...
} finally {
    System.setIn( old );
}
Juncaceous answered 28/9, 2010 at 14:59 Comment(1)
Small detail: since the bufferedreader is constructed without a charset, shouldn't you call getBytes() without a charset as well (or, of course, add a charset to the bufferedreader)?Graze
B
7

Instead of the suggestions above (edit: I noticed that Bart left this idea in a comment as well), I would suggest making your class more unit testable by making the class accept the input source as a constructor parameter or similar (inject the dependency). A class shouldn't be so coupled to System.in anyway.

If your class is constructed from a Reader, you can just do this:

class SomeUnit {
   private final BufferedReader br;
   public SomeUnit(Reader r) {
       br = new BufferedReader(r);
   }
   //...
}

//in your real code:
SomeUnit unit = new SomeUnit(new InputStreamReader(System.in));

//in your JUnit test (e.g.):
SomeUnit unit = new SomeUnit(new StringReader("here's the input\nline 2"));
Browbeat answered 28/9, 2010 at 15:4 Comment(0)
S
3

My solution currently (in 2018) is:

 final byte[] passCode = "12343434".getBytes();
 final ByteArrayInputStream inStream = new ByteArrayInputStream(passCode);
        System.setIn(inStream);

[Update in 2019] For JUnit4 Tests there is a framework for these tasks: https://stefanbirkner.github.io/system-rules/ (the upgrade to JUnit5 is on going: https://github.com/stefanbirkner/system-rules/issues/55)

Spiers answered 12/5, 2018 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.