I have only one method main. How to check System.out.println() and replace Scanner to input values automatically using JUnit?
P.S. Please, provide some solutions...
I faced a similar issue and this is what I ended up doing.
First off, I'd suggest doing as @Jon-Skeet suggests and instead of using the main(String[])
method of the class, create a separate method.
Then you can have that method take in an InputStream
as a parameter and then create a Scanner
object within the method that uses the passed InputStream
as its source. That way you can pass any InputStream
, such as System.in
, to the method when it's called (elaboration below).
package my.package;
import ...;
public class MyClass
{
public static void myMethod(InputStream inputStream)
{
Scanner inputScanner = new Scanner(inputStream);
// Do stuff with the Scanner such as...
String input = inputScanner.nextLine();
System.out.println("You inputted " + input);
}
}
Now, in your production source code you can call myMethod
and pass it System.in
as an argument as such, myMethod(System.in);
And then in your unit tests, you can create mock input values via a ByteArrayInputStream
:
package my.package;
import ...;
public class MyClassTest
{
@Test
void testMyMethod()
{
// Simulates a user inputting the string "Mock input" and hitting enter
assertDoesNotThrow(myMethod(new ByteArrayInputStream("Mock input\n".getBytes())));
}
}
And voila, you now have a way to pass your method mock input as well as it being more modular overall.
I just want to point out without getting too much into it, that when working with System.in
, one needs to be careful about closing it and in unit tests when working with input streams, one needs to be careful about reusing a reference to the same InputStream
as its state can persist across uses.
Ideally, extract the awkward dependencies so that you can test without them. Change main
to simply:
public static void main(String[] args) {
doWork(new Scanner(System.in), System.out);
}
// TODO: Rename to something meaningful
public static void doWork(Scanner input, PrintStream output) {
// Remainder of code
}
(Consider using a Writer
instead of a PrintStream
for output
.)
Then you don't really need to unit test main
- but you can test doWork
using a Scanner
based on a StringReader
, and output based on a StringWriter
, providing whatever input you want and checking the output.