目前正在编写JUnit测试,但在测试依赖用户输入的方法时遇到了困难。有没有一种方法可以在测试方法中"模拟"用户输入?我有这样的东西(我没有粘贴实际的代码,因为方法很长,超出了理解问题的范围;然而,我确实要求用户输入,如果错误,我会再次要求,直到输入正确的值):
public void method(){
System.out.println("Enter something");
int a = scanner.nextInt();
for(;;){
if(a!=10){
System.out.println("Please enter another value!");
a=sc.nextInt();
else{
break;
}
}
//further code
}
因为这是交互式的,所以很难很好地进行测试,或者至少以可读的方式进行测试。
测试类似代码的一种常见方法是提取一个包含Scanner和PrintWriter的方法,类似于StackOverflow的答案,并测试它:
public void method() {
method(new Scanner(System.in), System.out);
}
/** For testing. */
public void method(Scanner scanner, PrintWriter output) {
output.println("Enter something");
int a = scanner.nextInt();
// ...
}
这类似于使用System.setIn
分配新的stdin/stdout,但更具可预测性,并且需要更少的清理。然而,在这两种情况下,像nextInt
这样的方法在等待输入时都会阻塞。除非你想让这个测试成为多线程的(这很复杂),否则你直到最后都无法读取你的输出,你必须提前指定所有的指令:
@Test
public void methodShouldLaunchTheSpaceShuttle() {
StringWriter output = new StringWriter();
String input = "5n" // "Please enter another value!"
+ "10n" // "Code accepted. Enter command:"
+ "Shuttlen"; // "Launching space shuttle..."
systemUnderTest.method(new Scanner(input), new PrintWriter(output));
assertThat(output.toString(), contains("Please enter another value!"));
assertTrue(systemUnderTest.spaceShuttleLaunched());
}
也就是说,只要你的指令集是简单的(并且不会改变),你就可以添加注释(如上所述),并获得一个有价值的测试,将你的代码覆盖率提高到你需要的程度。
(注意:当然,与其创建重载方法,您还可以将"scanner"one_answers"output"作为系统中的可变字段进行测试。我倾向于尽可能保持类的无状态状态,但如果这对您或您的同事/讲师很重要,那也不是一个很大的让步。)
难道不能提供自己的测试值吗?他们只是int
,对吧?如果它们是基元值,您不需要模拟任何东西,只需在给定一组int
s:的情况下测试您的功能即可
public void method(){
int a = // your own test value, or even an array of test values
for(;;) {
if (a != 10){
// check against your test values
else{
break;
}
}
//further code
}
如果您依赖外部输入来让单元测试工作,那么这些并不是真正的单元测试。