'Junit method testing, user integer input

I don't know how to simulate user input for integers/floats/doubles inside a unit test. I used this to simulate a string input:

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

But I don't know how to enter an integer instead. This is the method I am testing:

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


Solution 1:[1]

I will use a random test example to explain the logic. You should create a wrapper for system input/output functions. You can do this using dependency injection, giving us a class that can ask for new integers:

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

Then you can create tests for your function, using a mock framework (In this example I am using 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.");
}

Then write your function that passes the tests. The function is much cleaner since you can remove the asking/getting integer duplication and the actual system calls are encapsulated.

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

Solution 2:[2]

So I figured it out. It can be done the same exact way as a string as this is just sending an input and not a specific type. In my case, the method I want to test is:

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

and the test I wrote is this:

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

I am not sure if this is the best/proper way to complete this but it was how I did it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 David Kariuki
Solution 2 BiggerOwO