控制台 I/O 重定向后清空 InputStream
Empty InputStream after console I/O redirection
我必须测试一个程序,用户必须在其中输入 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 args 来准备输入流。
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() 时,我都会使用非空参数字符串创建新的 InputStream。
我还尝试恢复默认 System.in 并在 set() 中再次重定向它 - 没有效果。
谁能解释一下我到底忘记了什么?
更新。我将我的代码分成方法来解释哪个是哪个,但以防它会增加可读性——下面是完全相同的代码:
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
}
更新。
这是堆栈跟踪:
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)
我知道异常的确切来源。
这是从 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
}
但是我不明白为什么IS是空的。
嗯。看来我解决了。
我刚刚将 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);
// ....
}
}
我必须测试一个程序,用户必须在其中输入 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 args 来准备输入流。
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() 时,我都会使用非空参数字符串创建新的 InputStream。 我还尝试恢复默认 System.in 并在 set() 中再次重定向它 - 没有效果。
谁能解释一下我到底忘记了什么?
更新。我将我的代码分成方法来解释哪个是哪个,但以防它会增加可读性——下面是完全相同的代码:
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
}
更新。 这是堆栈跟踪:
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)
我知道异常的确切来源。 这是从 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
}
但是我不明白为什么IS是空的。
嗯。看来我解决了。
我刚刚将 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);
// ....
}
}