为 Java 程序编写测试用例,该程序在迭代中接受用户输入以获得最终值

Writing a test case for a Java program which takes user input in iterations to get to a final value

下面是 java 程序,用于猜测汤姆有多少个苹果。如果汤姆的苹果数量比猜测的数量多,他会打得更高,如果比猜得少,他会打得更低。当猜对数字时,他会回复none。我的任务是为这个程序编写一个 JUnit 测试用例。由于基于用户输入,猜测的数字会递减或递增,直到我们达到实际值为止,这让我很困惑如何为这个程序编写 JUnit 测试用例

  public static void main(String args[]){
      System.out.println("Guess the number of Apples Tom has");
      Scanner sc= new Scanner(System.in);
      int number=sc.nextInt();
      System.out.println("Tom, is it higher or lower?");
      String higherOrLower=sc.nextLine();

      while(true){
          number= getValue(higherOrLower,number);
          System.out.println("Tom, is it higher or lower?");
          higherOrLower=sc.nextLine();
          if(higherOrLower.equalsIgnoreCase("none")) {
                break;
          }
      }
  }

  public static int getValue(String i,int j){

        if(i.equalsIgnoreCase("lower")) {
            j--;
            return j;
        } else if(i.equalsIgnoreCase("higher")) {
            j++;
            return j;
        } else {
            return j;
        }
    }

好的,让我们在这里详细介绍一下...

好的单元测试的基础是好的代码。这就解释了为什么编写单元测试不仅可以使代码工作更可靠,还可以使编码人员编写更好的代码(因为糟糕的代码通常很难测试)。

在您的示例中,您有两种方法(我假设您还没有深入了解面向对象编程 (OOP) 的细节,所以我不会讨论如何使用额外的 类).

一种方法进行实际的数字运算(好的,一点点运算),另一种方法进行输入。不幸的是,您的输入法也是您的主要方法,因此您可以做得更好一些,因为主要方法不太适合测试。

public static void main(String[] args) {

    Scanner scanner = new Scanner(System.in); // We'll ignore finer problems with scanners, etc. here
    playGame(scanner);

}

public static void playGame(Scanner scanner) {
    System.out.println("Guess the number of Apples Tom has");
    Scanner sc= new Scanner(System.in);
    int number=sc.nextInt();
    System.out.println("Tom, is it higher or lower?");
    String higherOrLower=sc.nextLine();

    while(true){
        number= getValue(higherOrLower,number);
        System.out.println("Tom, is it higher or lower?");
        higherOrLower=sc.nextLine();
        if(higherOrLower.equalsIgnoreCase("none")) {
            break;
        }
    }
}

这一小改动将使您的代码更易于测试。让我们从简单的部分开始,即 getValue 方法: @测试 public无效lower_should_return_number_minus_1(){ int result = getValue("lower", 10); Assert.assertEquals(9, 结果); // 简单断言 }

@Test
public void higher_should_return_number_plus_1() {
    int result = getValue("higher", 10);
    Assert.assertEquals(11, result); // simple assertions
}

@Test
public void garbage_should_return_same_number() {
    int result = getValue("Hello, Polly!", 10);
    Assert.assertEquals(10, result); // simple assertions
}

这将测试您的大部分可能性。如果您为字符串输入 null,最好也测试一下会发生什么,只是为了确定 ;-)

测试另一种方法会有点困难,因为它涉及一些小技巧...

@Test(timeout=1000)
public void game_should_work_on_input() {
    final ByteArrayInputStream stream = new ByteArrayInputStream(String.format("5%nlower%nlower%nnone%n").getBytes());
    final Scanner scanner = new Scanner(stream);
    playGame(scanner);
}

这里我们简单地创建一个"fake"输入,它由“5”、"lower"、"lower"和"none"组成(老实说,5之间有一个空行和第一个较低的)。 String.format 将为每个 %n 添加正确的新行字符。如果您的测试成功,则意味着游戏已经进行到最后。如果没有,超时将发生在 1000 毫秒之前(这意味着您的游戏没有正确结束,这是应该的)。老实说,没有测试过,但我敢肯定,你可以从那里开始。 ;-)