【问题标题】:Empty InputStream after console I/O redirection控制台 I/O 重定向后的空 InputStream
【发布时间】:2021-12-18 07:05:37
【问题描述】:

我必须测试一个程序,用户必须输入 3 个数字,然后他会在控制台输出中得到结果。

我编写了测试并重定向了 System.in 和 System.out。 我的测试用例如下所示:

private static ByteArrayOutputStream mockOut;

@Test
public void correct_input_test() {
    test("> x = 0, y = 0", 1, 0, 0);
    test("> x = -1, y = 0", 1, 0, -1);
}

这是预期的控制台输出作为第一个参数和 3 个 int 参数来准备输入流。

test()方法如下:

private static void test(String expected, int ... args) {
    set(args);       // preparing inputstream and redirecting Sys.i/o
    run(expected);   // running program test after setting up
}

根据需要允许尽可能多的整数输入。这些参数进一步传递给 set() 方法,我在该方法中创建输入流并重定向 System.in set() 方法:

private static void set(int... args) {
    String s = Arrays.stream(args)
               .mapToObj(String::valueOf)
               .collect(Collectors.joining(" "));          // assembling args String
    System.setIn(new ByteArrayInputStream(s.getBytes()));  // redirecting Sys.in 
    mockOut = new ByteArrayOutputStream();
    PrintStream stream = new PrintStream(mockOut);
    System.setOut(stream);                                 // redirecting Sys.out
}

传递的参数 1、0、0 变成了 String s = "1 0 0"

最后在设置之后我运行调用我的程序的方法

private static void run(String expected) {
    Main.main(null);                                              // call program to catch result
    String[] consoleLines = mockOut.toString().split("\n");       // split console output
    assertEquals(expected, consoleLines[consoleLines.length-1]);  // compare lines
}

在这里,我在 mockOut 对象中获得的单独的控制台输出行拆分,并将最后一行与预期的字符串进行比较。

只有在我测试一个测试用例时才有效(如果我注释掉这些测试用例中的任何一个)。

@Test
public void correct_input_test() {
//    test("> x = 0, y = 0", 1, 0, 0);
    test("> x = -1, y = 0", 1, 0, -1);
}

但是,如果我在第二次尝试调用程序之后尝试运行两者,它会得到一个带有 java.util.NoSuchElementException 的空输入流,我实际上不知道为什么。 我试图关闭流,但我想这没关系。每次我调用 set() 时,我都会使用非空的 args-string 创建新的 InputStream。 我还尝试恢复默认 System.in 并在 set() 中再次重定向它 - 没有效果。

谁能解释一下我到底忘记了什么?

UPD。我将我的代码与方法分开来解释哪个是哪个,但以防它会增加可读性 - 下面是完全相同的代码:

private static ByteArrayOutputStream mockOut;

@Test
public void correct_input_test() {
    test("> x = 0, y = 0", 1, 0, 0);
    test("> x = -1, y = 0", 1, 0, -1);
}

private static void test(String expected, int ... args) {
    set(args);       // preparing inputstream and redirecting Sys.i/o
    run(expected);   // running program test after setting up
}

private static void set(int... args) {
    String s = Arrays.stream(args)
               .mapToObj(String::valueOf)
               .collect(Collectors.joining(" "));          // assembling args String
    System.setIn(new ByteArrayInputStream(s.getBytes()));  // redirecting Sys.in 
    mockOut = new ByteArrayOutputStream();
    PrintStream stream = new PrintStream(mockOut);
    System.setOut(stream);                                 // redirecting Sys.out
}

private static void run(String expected) {
    Main.main(null);                                              // call program to catch result
    String[] consoleLines = mockOut.toString().split("\n");       // split console output
    assertEquals(expected, consoleLines[consoleLines.length-1]);  // compare lines
}

UPD。 这是堆栈跟踪:

java.util.NoSuchElementException: 

Arguments input incomplete.

    at Main.in(Main.java:169)
    at Main.main(Main.java:19)
    at MainTest$MainMethodTest.run(MainTest.java:75)
    at MainTest$MainMethodTest.test(MainTest.java:71)
    at MainTest$MainMethodTest$SwapMethodTest.correct_input_test(MainTest.java:29)

我知道异常的确切来源。 这是从 ma​​in() 调用以获取用户输入的 in() 方法,当 Scanner 尝试读取 next() 时捕获的异常输入流:

public static int in(String message, int from, int to) {
    if (message != null && !message.isEmpty()) {
        System.out.print(message);
    }
    try {
        String input = scanner.next();
        int num;

        /*         this code works correctly for me
                   and is just to check 
                   if user typed correct number 
                   and if the number is in range.
        try {
            if ((num = Integer.parseInt(input)) < from) {
                throw new IllegalArgumentException("\n\nExpected: value >= " + from + "\nActual:   value = " + num + "\n");
            } else if (num > to) {
                throw new IllegalArgumentException("\n\nExpected: value <= " + to + "\nActual:   value = " + num + "\n");
            } else {
                return num;
            }
        } catch (NumberFormatException e) {
            throw new NumberFormatException("\n\nExpected: integer number\nActual:   " + input + "\n");
        }
        */

    } catch (NoSuchElementException e) {
        throw new NoSuchElementException("\n\nArguments input incomplete.");
    }   // at Main.in(Main.java:169) - here is line 169
}

但我不明白为什么 IS 是空的。

【问题讨论】:

  • 抛出异常的堆栈跟踪是什么?
  • 是的,我更新了帖子。谢谢

标签: java junit console inputstream


【解决方案1】:

嗯。看来我解决了。

我刚刚将 Scanner 初始化从变量声明移到 main()。

public class Main {
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        // ....
    }
}

现在它对我有用。

public class Main {
    private static Scanner scanner;

    public static void main(String[] args) {
        scanner = new Scanner(System.in);
        // ....
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    相关资源
    最近更新 更多