Wim*_*pey 72 java eclipse junit user-input
我正在尝试为需要用户输入的方法创建一些JUnit测试.测试中的方法看起来有点像以下方法:
public static int testUserInput() {
Scanner keyboard = new Scanner(System.in);
System.out.println("Give a number between 1 and 10");
int input = keyboard.nextInt();
while (input < 1 || input > 10) {
System.out.println("Wrong number, try again.");
input = keyboard.nextInt();
}
return input;
}
Run Code Online (Sandbox Code Playgroud)
是否有可能在JUnit测试方法中自动将程序传递给int而不是我或其他人手动执行此操作?像模拟用户输入一样?
提前致谢.
Krz*_*zyH 91
您可以通过调用System.setIn(InputStream in)将System.in替换为您自己的流.输入流可以是字节数组:
InputStream sysInBackup = System.in; // backup System.in to restore it later
ByteArrayInputStream in = new ByteArrayInputStream("My string".getBytes());
System.setIn(in);
// do your thing
// optionally, reset System.in to its original
System.setIn(sysInBackup);
Run Code Online (Sandbox Code Playgroud)
通过传入IN和OUT作为参数,不同的方法可以使这种方法更具可测性:
public static int testUserInput(InputStream in,PrintStream out) {
Scanner keyboard = new Scanner(in);
out.println("Give a number between 1 and 10");
int input = keyboard.nextInt();
while (input < 1 || input > 10) {
out.println("Wrong number, try again.");
input = keyboard.nextInt();
}
return input;
}
Run Code Online (Sandbox Code Playgroud)
Gar*_*all 16
要测试驱动代码,您应该为系统输入/输出函数创建一个包装器.你可以使用依赖注入来实现这一点,为我们提供一个可以请求新整数的类:
public static class IntegerAsker {
private final Scanner scanner;
private final PrintStream out;
public IntegerAsker(InputStream in, PrintStream out) {
scanner = new Scanner(in);
this.out = out;
}
public int ask(String message) {
out.println(message);
return scanner.nextInt();
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用模拟框架为我的函数创建测试(我使用Mockito):
@Test
public void getsIntegerWhenWithinBoundsOfOneToTen() throws Exception {
IntegerAsker asker = mock(IntegerAsker.class);
when(asker.ask(anyString())).thenReturn(3);
assertEquals(getBoundIntegerFromUser(asker), 3);
}
@Test
public void asksForNewIntegerWhenOutsideBoundsOfOneToTen() throws Exception {
IntegerAsker asker = mock(IntegerAsker.class);
when(asker.ask("Give a number between 1 and 10")).thenReturn(99);
when(asker.ask("Wrong number, try again.")).thenReturn(3);
getBoundIntegerFromUser(asker);
verify(asker).ask("Wrong number, try again.");
}
Run Code Online (Sandbox Code Playgroud)
然后编写通过测试的函数.该函数更清晰,因为您可以删除询问/获取整数重复并封装实际的系统调用.
public static void main(String[] args) {
getBoundIntegerFromUser(new IntegerAsker(System.in, System.out));
}
public static int getBoundIntegerFromUser(IntegerAsker asker) {
int input = asker.ask("Give a number between 1 and 10");
while (input < 1 || input > 10)
input = asker.ask("Wrong number, try again.");
return input;
}
Run Code Online (Sandbox Code Playgroud)
对于你的小例子来说,这似乎有些过分,但如果你正在构建一个更大的应用程序,这样的开发可以很快得到回报.
测试类似代码的一种常用方法是提取一个接收Scanner和PrintWriter的方法,类似于此StackOverflow答案,并测试:
public void processUserInput() {
processUserInput(new Scanner(System.in), System.out);
}
/** For testing. Package-private if possible. */
public void processUserInput(Scanner scanner, PrintWriter output) {
output.println("Give a number between 1 and 10");
int input = scanner.nextInt();
while (input < 1 || input > 10) {
output.println("Wrong number, try again.");
input = scanner.nextInt();
}
return input;
}
Run Code Online (Sandbox Code Playgroud)
请注意,在结束之前您将无法读取输出,并且您必须预先指定所有输入:
@Test
public void shouldProcessUserInput() {
StringWriter output = new StringWriter();
String input = "11\n" // "Wrong number, try again."
+ "10\n";
assertEquals(10, systemUnderTest.processUserInput(
new Scanner(input), new PrintWriter(output)));
assertThat(output.toString(), contains("Wrong number, try again.")););
}
Run Code Online (Sandbox Code Playgroud)
当然,您可以将"扫描仪"和"输出"保留为被测系统中的可变字段,而不是创建重载方法.我倾向于将课程视为无国籍,但如果对你或你的同事/导师来说这不是很大的让步.
您也可以选择将测试代码放在与测试代码相同的Java包中(即使它位于不同的源文件夹中),这样您就可以放宽对两个参数重载的可见性,使其成为package-private.
| 归档时间: |
|
| 查看次数: |
78387 次 |
| 最近记录: |