0

I am trying to use the same input from the unit test throughout the entire program, but the program has different scanner instances across its functions and classes and the input stream withdrawn from the string only works at the very first scanner but not the rest.

import java.io.ByteArrayInputStream;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        String data = "1\nThis is the first input\nThis is the second input";

        ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes());
        System.setIn(is);
        
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.nextLine());
        scanner.close();

        func();
    }

    private static void func() {
        Scanner scanner = new Scanner(System.in);

        System.out.println("First input: " + scanner.nextLine());
        System.out.println("Second input: " + scanner.nextLine());

        scanner.close();
    }
}

This is a representation of the issue I am facing, my real version has more complex foundation, but the end result is the same.

1
Exception in thread "main" java.util.NoSuchElementException: No line found
        at java.base/java.util.Scanner.nextLine(Scanner.java:1651)
        at Main.func(Main.java:21)
        at Main.main(Main.java:15)
Aoof
  • 322
  • 2
  • 10
  • 2
    try do design your system for testability: Don't instanciate a new `Scanner` everywhere you need it, but pass it into your functions as parameter. So for the tests you can either use a mocked scanner or prepare a Scanner with an `InputStream` that represents your test input. But you will have either to reset that InputStream or create a new one per test. – cyberbrain May 12 '23 at 19:34
  • cyberbrain I tried to pass it through and was faced with the same issue but let me try it out again and see if it worked then update the thread appropriately. – Aoof May 12 '23 at 19:57
  • What thread do you mean? – aled May 12 '23 at 20:20

1 Answers1

1

try do design your system for testability: Don't instanciate a new Scanner everywhere you need it, but pass it into your functions as parameter. So for the tests you can either use a mocked scanner or prepare a Scanner with an InputStream that represents your test input. But you will have either to reset that InputStream or create a new one per test. – cyberbrain

This is based on cyberbrain’s suggestion, passing the scanner as a parameter to every function that may require a scanner was the solution, now it is optimized for testability and we can use string input unit tests without any issues

import java.io.ByteArrayInputStream;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        String data = "1\nThis is the first input\nThis is the second input";

        ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes());
        System.setIn(is);
        
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.nextLine());

        func(scanner);

        scanner.close();
    }

    private static void func(Scanner scanner) {
        System.out.println("First input: " + scanner.nextLine());
        System.out.println("Second input: " + scanner.nextLine());
    }
}
Aoof
  • 322
  • 2
  • 10
  • 1
    is this your solution, or how you tried to solve the problem? If it's your trial to solve the problem, please [edit](https://stackoverflow.com/posts/76239380/edit) your question instead of adding an answer that isn't one. If it solved your problem, please accept your own answer (and as a bonus add some words to it that make that clear ;-) – cyberbrain May 14 '23 at 10:41
  • it was the solution but I needed 2 days to accept the answer. I don’t believe I can word it better than you did but I’ll add more to it. – Aoof May 15 '23 at 14:33