首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用模拟用户输入进行JUnit测试

使用模拟用户输入进行JUnit测试
EN

Stack Overflow用户
提问于 2011-06-21 02:28:21
回答 7查看 113K关注 0票数 87

我正在尝试为一个需要用户输入的方法创建一些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;
}

有没有可能自动向程序传递一个int,而不是我或其他人在JUnit测试方法中手动执行此操作?比如模拟用户输入?

提前谢谢。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2011-06-21 03:11:12

您可以替换System.in with you own stream by calling System.setIn(InputStream in)。InputStream可以是字节数组:

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

不同方法可以通过传入和传出作为参数来使此方法更具可测试性:

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;
}
票数 111
EN

Stack Overflow用户

发布于 2011-06-21 03:46:40

为了测试你的代码,你应该为系统输入/输出函数创建一个包装器。你可以使用依赖注入来做这件事,给我们一个可以请求新整数的类:

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

然后,您可以使用模拟框架(我使用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.");
}

然后编写通过测试的函数。这个函数要干净得多,因为您可以删除询问/获取整数的重复,并且实际的系统调用是封装的。

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

对于您的小示例来说,这可能看起来有点过头了,但如果您正在构建一个更大的应用程序,那么开发这样的应用程序可能会相当快地获得回报。

票数 18
EN

Stack Overflow用户

发布于 2014-04-29 11:11:22

测试类似代码的一种常见方法是提取一个接受扫描器和PrintWriter (类似于this StackOverflow answer )的方法,并测试该方法:

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

请注意,直到最后才能读取输出,并且必须在前面指定所有输入:

@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.")););
}

当然,您也可以将"scanner“和"output”作为系统中的可变字段进行测试,而不是创建一个重载方法。我倾向于尽可能保持类的无状态,但如果这对您或您的同事/讲师很重要,这并不是一个很大的让步。

您还可以选择将测试代码放在与测试代码相同的Java包中(即使它位于不同的源文件夹中),这允许您将两个参数重载的可见性放宽为包私有。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6415728

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档