【问题标题】:JUnit Tests: User Input [duplicate]JUnit 测试:用户输入
【发布时间】:2014-06-14 14:20:20
【问题描述】:

目前正在编写 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
   }

【问题讨论】:

    标签: unit-testing junit user-input


    【解决方案1】:

    您不能只提供自己的测试值吗?他们只是ints 对吗?如果它们是原始值,则无需模拟任何内容,只需给定一组 ints 即可测试您的功能:

    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
    }
    

    如果您依靠外部输入来使单元测试发挥作用,那么这些就不是真正的单元测试。

    【讨论】:

    • 我已经这样做了,但我需要这些显示在代码覆盖率统计中。
    【解决方案2】:

    因为这是交互式的,所以可能很难很好地测试——或者,至少,以一种可读的方式。

    测试类似代码的一种常见方法是提取一个接受 Scanner 和 PrintWriter 的方法,类似于this StackOverflow answer,然后测试:

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

    这类似于assigning a new stdin/stdout using System.setIn,但更可预测,并且需要更少的清理。但是,在这两种情况下,nextInt 之类的方法都会在等待输入时阻塞。除非你想让这个测试多线程(这很复杂),否则你将无法读取你的输出直到最后,你必须预先指定所有指令:

    @Test
    public void methodShouldLaunchTheSpaceShuttle() {
      StringWriter output = new StringWriter();
      String input = "5\n"        // "Please enter another value!"
                   + "10\n"       // "Code accepted. Enter command:"
                   + "Shuttle\n"; // "Launching space shuttle..."
      systemUnderTest.method(new Scanner(input), new PrintWriter(output));
    
      assertThat(output.toString(), contains("Please enter another value!"));
      assertTrue(systemUnderTest.spaceShuttleLaunched());
    }
    

    也就是说,只要您的指令集简单明了(并且不会更改),您就可以添加 cmets(如上所述)并获得有价值的测试,从而将您的代码覆盖率提高到您需要的水平。

    (注意:当然,除了创建重载方法之外,您还可以将“扫描仪”和“输出”作为可变字段保留在您的系统中进行测试。我倾向于尽可能保持类无状态,但这是如果对你或你的同事/导师很重要,这不是一个很大的让步。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-18
      • 2023-03-17
      • 2015-04-30
      • 1970-01-01
      • 2019-08-17
      • 2019-10-13
      • 1970-01-01
      相关资源
      最近更新 更多