0

I have a method which asks the user to choose a number between 1 and 7. It uses the Scanner class to take the users input as an int. I saw how to code this for a string, but how would I modify that for int? My method is...

/** * This method asks the player to choose a column 1-7. If the player enters a number

  • outside this range
    • the method will continually ask until a correct number is entered. The column is
  • decreased by one to account for
    • arrays starting at 0 and returned
    • @param turn Player which ever players turn it is, is asked for a column
    • @return int the column is returned after lowered by one */
      
      System.out.println("\n\n" + turn.getTag() + " please enter the column number, 1-7,  \n"
              + "where you would like to drop your game piece. ");
      boolean colCorrect = false;
      int column = -1;
      while (!colCorrect){
          if(Connect4TextConsole.in.hasNextInt()){
              column = Connect4TextConsole.in.nextInt();
              colCorrect = true;}
          else{ System.out.println("Please enter a number 1 through 7.");
              Connect4TextConsole.in.next();}}
      while(column < 1 || column > 7) {
          System.out.println("Please enter a number 1 through 7.");
          column = Connect4TextConsole.in.nextInt();
      }
      return column - 1; // subtract one to account for array starting at zero
      }``` 
      
Lyes
  • 335
  • 2
  • 15
  • Does this answer your question? [JUnit: How to simulate System.in testing?](https://stackoverflow.com/questions/1647907/junit-how-to-simulate-system-in-testing) – andreoss Jul 01 '20 at 00:55
  • You can use the junit timeout to test the case when the user gives an out of range number, so if the method finishs by a timeout exception your method is well because the while loop retain user until he gives the right number. To simulate the user input you can replace System.in of your scanner by an instance of InputStream so you can provide a test input as it's explained in this [answer](https://stackoverflow.com/questions/6415728/junit-testing-with-simulated-user-input) – Lyes Jul 01 '20 at 00:58

1 Answers1

0

You don't need to test Java's API when testing your code: you can assume Scanner works (for example).

Probably the most flexible way to achieve this would be to inject a Scanner into the class handling user input and then mock that scanner in your test code:

class InputHandler {
    private final Scanner input;

    public InputHandler(Scanner input) {
        this.input = input;
    }

    public void nextChoice() {
        int choice = input.nextInt();
        ...
    }
}

Then your production code would look like:

InputHandler inputHandler = new InputHandler(new Scanner(System.in));

And your test code would look like:

@Test void option2() {
    Scanner input = mock(Scanner.class);
    when(input.nextInt()).thenReturn(2);
    InputHandler testHandler = new InputHandler(input);
    ...
}

@Test void illegalInput() {
    Scanner input = mock(Scanner.class);
    when(input.nextInt()).thenThrow(InputMismatchException.class);
    InputHandler testHandler = new InputHandler(input);
    ...
}

If you particularly want to test that your prompts are correct then you could also inject a PrintStream for output and mock that as well:

@Test
void testChoicePrompt() {
    Scanner input = mock(Scanner.class);
    PrintStream output = mock(PrintStream.class);
    InputHandler inputHandler = new InputHandler(input, output);
    inputHandler.nextChoice();
    verify(output).println("Enter choice:");
}        
sprinter
  • 24,103
  • 5
  • 40
  • 71