我必须测试一个程序,用户必须输入3个数字,然后他在控制台输出中得到结果。
我编写了测试并重定向了系统。在和系统中。出来我的测试用例如下所示:
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()方法,在该方法中,我创建了一个Input流并重定向System.inset()方法:
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变成字符串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。我不知道为什么。我试过关闭溪流,但我想没关系。每次调用set()时,我都会使用非空的参数字符串创建新的InputStream。我还试图恢复默认系统。并在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)
我知道异常的确切来源。这是in()方法,它从main()调用以获取用户的输入,并且当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
}
但我不明白为什么是空的。
好看来我解决了。
我刚刚将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个"文件"处于打开状态, stdin(键盘),stdout(屏幕), andstderr(错误消息输出到屏幕上). 这3个文件和其他打开的文件都可以被重定向. 对于重定向简单的解释就是捕捉一个文件, 命令, 程序, 脚本, 或者甚至是脚本中的代码块(参见 Example 3-1和 Example 3-2)的输出, 然后将这些输出作为输入发送到另一个文件, 命令, 程序, 或脚本中
所以,我的代码是 但是控制台是空的。没有错误,什么都没有。我做错了什么?
有如 while, until, 和 for 循环, 甚至 if/then 也可以重定向 标准输入 测试代码块. 甚至连一个函数都可以用这个方法进行重定向 (见 样例 24-11). 代码块的末尾部分的 “<” 就是用来完成这个的. 样例 20-5. while 循环的重定向 #!/bin/bash # redir2.sh if [ -z "$1" ] then Filename=names.
限制模式下被禁用的命令 在限制模式下运行一个脚本或部分脚本将禁用一些命令,尽管这些命令在正常模式下是可用的。这是个安全措施,可以限制脚本用户的权限,减少运行脚本可能带来的损害。 被禁用的命令和功能: 使用 cd 来改变工作目录。 修改 $PATH, $SHELL, $BASH_ENV 或 $ENV 等环境变量 读取或修改 $SHELLOPTS,shell环境选项。 输出重定向。 调用包含 / 的命
一个 exec < filename 命令重定向了 标准输入 到一个文件。自此所有 标准输入 都来自该文件而不是默认来源(通常是键盘输入)。在使用 sed 和 awk 时候这种方式可以逐行读文件并逐行解析。 样例 20-1. 使用 exec 重定向 标准输入 #!/bin/bash # 使用 'exec' 重定向 标准输入 . exec 6<&0 # 链接文件描述符 #6 到标准
and 列表 和 or 列表 结构提供了连续执行若干命令的方法,可以有效地替换复杂的嵌套 if/then ,甚至 case 语句。 链接多个命令 and 列表 command-1 && command-2 && command-3 && ... command-n 只要前一个命令返回 true(即 0),每一个命令就依次执行。当第一个 false(即 非0)返回时,命令链条即终止(第一个返回 fa