简体   繁体   English

控制台 I/O 重定向后的空 InputStream

[英]Empty InputStream after console I/O redirection

I have to test a program, where user have to enter 3 numbers and then he get result in console output.我必须测试一个程序,用户必须输入 3 个数字,然后在控制台输出中得到结果。

I wrote test and redirected System.in and System.out.我编写了测试并重定向了 System.in 和 System.out。 My test cases look like this:我的测试用例如下所示:

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);
}

Here's expected console output as first argument and 3 int args to prepare input stream.这是预期的控制台输出作为第一个参数和 3 个 int args 来准备输入流。

test() method is below: 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
}

As many integer inputs are allowed as needed.根据需要允许尽可能多的整数输入。 These args passed further to set() method where I create an Input stream and redirect System.in set() method:这些参数进一步传递给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
}

Passed arguments 1, 0, 0 became a String s = "1 0 0"传递的参数 1, 0, 0 变成了字符串 s = "1 0 0"

And finally after set I run method that invokes my program最后在设置后我运行调用我的程序的方法

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
}

Here I split on separate lines console output that I get in mockOut object and compare the last line with expected string.在这里,我将在 mockOut 对象中获得的单独行控制台输出拆分,并将最后一行与预期字符串进行比较。

It works only if I test one testcase (if I comment out any of these testcases).它只有在我测试一个测试用例时才有效(如果我注释掉这些测试用例中的任何一个)。

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

But if I try to run both after the second try to invoke program it gets an empty input stream with java.util.NoSuchElementException and I actually don't know why.但是,如果我在第二次尝试调用程序后尝试同时运行这两个程序,它会得到一个带有java.util.NoSuchElementException的空输入流,我实际上不知道为什么。 I've tried to close streams but I guess it doesn't matter.我试图关闭流,但我想这无关紧要。 Each time I call set() I create new InputStream with non-empty args-string.每次我调用set() 时,我都会用非空的 args-string 创建新的 InputStream。 I also tried to restore default System.in and redirect it again in set() - no effect.我还尝试恢复默认 System.in 并在set() 中再次重定向它 - 无效。

Could anyone explain what exactly did I forget?谁能解释一下我到底忘记了什么?

UPD.更新。 I Separated my code to methods to explain which is which but in case it will increase readability - here is whole same code below:我将我的代码与方法分开来解释哪个是哪个,但如果它会增加可读性 - 下面是完全相同的代码:

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.更新。 Here is stack trace:这是堆栈跟踪:

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)

I know where exactly exception comes from.我知道异常究竟来自哪里。 Here is in() method that called from main() to get input from user and exception caught when Scanner tries to read next() from input stream:这是从main()调用的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
}

But I don't understand why IS is empty.但我不明白为什么 IS 是空的。

Well.好。 Seems I solved it.看来我解决了。

I just moved Scanner initialization from variable declaration to main().我只是将 Scanner 初始化从变量声明移到 main()。

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

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

And now it works for me.现在它对我有用。

public class Main {
    private static Scanner scanner;

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM