3

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...

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int[] arr = new int[4];

    for (int i = 0; i < arr.length; i++) {
        arr[i] = scanner.nextInt();
    }

    for (int i = 0; i < arr.length; i++) {
        int res = 0;
        int k = 0;
        int num = arr[i];
        /*.....*/
        System.out.println(num);
    }
}
1
  • I wanna learn how to work with it Commented Sep 16, 2012 at 6:31

2 Answers 2

7

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.

Sign up to request clarification or add additional context in comments.

4 Comments

How can I use this to have for example, multiple inputs corresponding to multiple prompts for information?
I have the same question. Let me know if you found something...!
@Aman: Sorry, I must have not seen this comment before. You'd provide a Scanner that returns all the values you'd expect the user to enter, basically.
Thanks. But I used the System Rules library stefanbirkner.github.io/system-rules
2

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()
    {
        byte[] inputBytesStub = "Simulated input\n".getBytes();
        ByteArrayInputStream inputStreamStub = new ByteArrayInputStream(inputBytesStub);
        // Simulates a user inputting the string "Simulated input" and hitting enter
        assertDoesNotThrow(myMethod(inputStreamStub));
    }
}

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.