junit testing for user input using Scanner

I have to test a method in a class which takes an input using Scanner class.

package com.math.calculator;

import java.util.Scanner;

public class InputOutput {

    public String getInput() {
        Scanner sc = new Scanner(System.in);
        return sc.nextLine();
    }
}

I want to test it using JUnit but not sure how to do it.

I tried using the following code but it wont work.

package com.math.calculator;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class InputOutputTest {

    @Test
    public void shouldTakeUserInput() {
        InputOutput inputOutput= new InputOutput();

        assertEquals("add 5", inputOutput.getInput());
    }
}

I want to also try it with Mockito (using mock... when ... thenReturn) but not sure how to do it.


Solution 1:

You can change the System.in stream using System.setIn() method.

Try this,

@Test
public void shouldTakeUserInput() {
    InputOutput inputOutput= new InputOutput();

    String input = "add 5";
    InputStream in = new ByteArrayInputStream(input.getBytes());
    System.setIn(in);

    assertEquals("add 5", inputOutput.getInput());
}

You have just modified the System.in field. System.in is basically an InputStream which reads from the console (hence your input in the console). But you just modified it and let the system to read from the provided inputstream instead. So it wont read from console anymore but from the inputstream provided.

Solution 2:

You can write a clear test for the command line interface by using the TextFromStandardInputStream rule of the System Rules library.

public void MyTest {
  @Rule
  public final TextFromStandardInputStream systemInMock
    = emptyStandardInputStream();

  @Test
  public void shouldTakeUserInput() {
    systemInMock.provideLines("add 5", "another line");
    InputOutput inputOutput = new InputOutput();
    assertEquals("add 5", inputOutput.getInput());
  }
}