Search code examples
javaunit-testingmockingjava.util.scannerinputstream

How to Mock the System.in Stream for a Unit Test


im really new to programming and want to ask how to mock the System.in Stream for a Unit-Test. My task is to programm the game and unit test the existing Methods. I dont know how to unit test a Method requiring an Input Stream. More Specific: I dont know how to mock it. In the following Code example is my method. The method reads in 4 accepted color-Strings with a Scanner and returns the Strings in an String-Array. Is there any Method to mock the System.in Stream

public String[] guess(){ //Read in the 4 colors a player want to guess
        int k = 1;
        Scanner valueIn = new Scanner(System.in);
        String[] guess = new String[4];
        for(int i = 0; i < 4;i++){
            k = 1;
            while(k==1) {
                System.out.println("now the " + (i + 1) + "color ");
                guess[i] = valueIn.nextLine();
                if(guess[i].equals("red")||guess[i].equals("blue")||guess[i].equals("yellow")||guess[i].equals("green")||guess[i].equals("purple")||guess[i].equals("brown")){
                    k = 0;
                }
            }
        }
        return guess;
    }

Solution

  • Use System.setIn() method.

    @Test
    public void test(){
        String[] expectedOutputArray = {"red", "green", "yellow", "brown"};
        String input = "red\ngreen\nyellow\nbrown";
        InputStream in = new ByteArrayInputStream(input.getBytes());
        System.setIn(in);
        String[] outputArray = guess(); //call your guess function
        Assert.assertArrayEquals(expectedOutputArray, outputArray);
    }
    
    • System.in is basically an InputStream which reads from the console (hence your input in the console).
    • So prepare an InputStream and set to in property of System class, using System.setIn(in)

    I am putting another approach for how the code can be reformatted for testing guess method, removing dependency on System.in

    Please put each class, in different java file

    public class GuessRefactor {
        private SystemClass systemObj;
    
        public String[] guess(SystemClass systemObj){
            int k = 1;
            String[] guess = new String[4];
            for(int i = 0; i < 4;i++){
                k = 1;
                while(k==1) {
                    System.out.println("now the " + (i + 1) + "color ");
                    guess[i] = systemObj.getInput();
                    if(guess[i].equals("red")||guess[i].equals("blue")||guess[i].equals("yellow")||guess[i].equals("green")||guess[i].equals("purple")||guess[i].equals("brown")){
                        k = 0;
                    }
                }
            }
            return guess;
        }
    
        public static void main(String[] args) {
            System.out.println(Arrays.toString(new GuessRefactor().guess(new SystemClass())));
        }
    }
    
    
    public class SystemClass {
        Scanner valueIn = new Scanner(System.in);
    
        public String getInput(){
            return valueIn.nextLine();
        }
    }
    
    
    @RunWith(MockitoJUnitRunner.class)
    public class TestClass {
        @Mock
        SystemClass systemClass;
    
        @Test
        public void test(){
            GuessRefactor guessRefactor = new GuessRefactor();
            Mockito.when(systemClass.getInput()).thenReturn("red");
            String[] expectedOutput = {"red", "red", "red", "red",};
            String[] output = guessRefactor.guess(systemClass);
            Assert.assertArrayEquals(expectedOutput, output);
        }
    }