Home > database >  Testing a method, that in the middle requires user's input - JUnit
Testing a method, that in the middle requires user's input - JUnit

Time:06-18

I need to test a method (i.e. also the methods that are called by him) with JUnit. The problem is that the "parent" method requires user's input from keyboard in the middle of the code lines: the input doesn't get passed to other methods, but is handled in the same method that is running and getting tested.

I know I could be using

String input = "sampleString";
InputStream in = new ByteArrayInputStream(input.getBytes());
System.setIn(in);
assertEquals(sampleString, Obj.inputReader("sampleString"));

but as far as I know this can't be done since if the code is the following:

public class MyClass{
  public int readInt() {
      Scanner scan = new Scanner(System.in);
      System.out.print("Enter number: ");
      int num = scan.nextInt();
      scan.close();
      return num;
  }
}

@Test
public void testmethod() throws IOException {
    MyClass myclass = new Myclass();
    myclass.readInt();
    String input = "4";
    InputStream in = new ByteArrayInputStream(input.getBytes());
    System.setIn(in);
    assertEquals(4, Obj.inputReader(parseToInt("4")));

the test keeps running since no keyboard input is received and it's impossible to reach the following line.

Does anybody know a method or suggest a path to get it done?

Thanks in advance to everybody!

CodePudding user response:

First your test is wrong. You call

myclass.readInt();

but never read the result. But back to your question.

You can achieve this with Mocks take a look for e.g Mockito.

You can Mock the Scanner Class and mock the scan.nextInt(); Call.

Like: if someone call "scan.nextInt()" just return prepared value.

Scanner listMock = Mockito.mock(Scanner.class); doReturn(4).when(listMock).nextInt();

CodePudding user response:

Your test does not use the result of readInt() and receives no input because you are setting System.setIn(in); after calling readInt().

class InputTest {
   @Test
   public void testMethod() throws IOException {
      // arrange
      String input = "4";
      InputStream in = new ByteArrayInputStream(input.getBytes());
      System.setIn(in);

      // act
      MyClass myclass = new MyClass();
      int num = myclass.readInt();

      // assert
      assertEquals(4, num);
   }

   @Test
   public void testMethodInject() throws IOException {
      // arrange
      String input = "4";
      InputStream in = new ByteArrayInputStream(input.getBytes());
      Scanner scanner = new Scanner(in);

      // act
      MyClass myclass = new MyClass();
      int num = myclass.readIntInjected(scanner);

      // assert
      assertEquals(4, num);
   }
}

It may be more easly testable if you inject Scanner object instead of creating it.

class MyClass {
   public int readInt() {
      Scanner scan = new Scanner(System.in);
      System.out.print("Enter number: ");
      int num = scan.nextInt();
      scan.close();
      return num;
   }

     // more easly testable
   public int readIntInjected(Scanner scanner) {
      System.out.print("Enter number: ");
      int num = scanner.nextInt();
      scanner.close();
      return num;
   }
}
  • Related