Junit方法测试,用户整数输入

Junit method testing, user integer input

我不知道如何在单元测试中为 integers/floats/doubles 模拟用户输入。我用它来模拟字符串输入:

@Test
public void testSetName() {
    String expectedResult = "Jason";
    InputStream in = new ByteArrayInputStream(expectedResult.getBytes());
    System.setIn(in);
    assertEquals(expectedResult, MainClass.setName());
}

但我不知道如何输入整数。 这是我正在测试的方法:

public static int setAge() {
    Scanner input = new Scanner(System.in);
    int age = 0;
    boolean done = false;
    while (!done) {
        System.out.print("Age: ");
        try {
            age = input.nextInt();
            done = true;
        } catch (InputMismatchException e) {
            System.out.println("Please enter a valid age!");
            input.nextLine();
        }
    }
    return age;
}

所以我想通了。它可以以与字符串完全相同的方式完成,因为这只是发送一个输入而不是特定类型。就我而言,我要测试的方法是:

public static int setAge() {
    Scanner input = new Scanner(System.in);
    int age = 0;
    boolean done = false;
    while (!done) {
        System.out.print("Age: ");
        try {
            age = input.nextInt();
            done = true;
        } catch (InputMismatchException e) {
            System.out.println("Please enter a valid age!");
            input.nextLine();
        }
    }
    return age;
}

我写的测试是这样的:

@Test
public void testSetAge() {
    String expectedResult = "5";
    InputStream in = new ByteArrayInputStream(expectedResult.getBytes());
    System.setIn(in);
    assertEquals(5, MainClass.setAge());
}

我不确定这是否是 best/proper 完成此操作的方法,但我就是这样做的。

我会用一个随机的测试例子来解释逻辑。您应该为系统 input/output 函数创建一个包装器。你可以使用依赖注入来做到这一点,给我们一个可以请求新整数的 class:

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

然后编写通过测试的函数。该函数更加简洁,因为您可以删除 asking/getting 整数重复,并且封装了实际的系统调用。

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