4

Can you please help me in writing the Junit test case for the below code?

public class ConsoleReader implements InputReader {
    public Cell readInput() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("Enter the co-ordinate Seperated by Comma");
            String coOrdinates = reader.readLine();
            String[] values=coOrdinates.split("\\,");
            return new Cell(Integer.parseInt(values[0]),Integer.parseInt(values[1]));
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return null;
    }
}
Sunny
  • 858
  • 3
  • 17
  • 39
  • 1
    Insteed of `new InputStreamReader(System.in)` pass `System.in` as method argument so you will be able to actually push data into the stream. – Antoniossss Nov 20 '18 at 12:10
  • Possible duplicate of [Mocking Java InputStream](https://stackoverflow.com/questions/6371379/mocking-java-inputstream) – Renny Nov 20 '18 at 13:01
  • 1
    as Antoniossss has suggested the best solution (even from design perspective). if you dont like that solution , there is a tricky/dirty solution. use the System.setIn and set a mock inputstream , once your test case is executed restore the system.in using the same method. this will work only in environment you dont have securitymanger or you have permission to setIO – hunter Nov 20 '18 at 13:57

2 Answers2

3
  1. Extract the reader as a field. (You can initiaize it either directly or in constructor)

    private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    
  2. Define a getter (either public or protected)

    protected BufferedReader getReader(){
        return reader;
    }
    
  3. Remove initialization of new BufferedReader(...) from your method. Retrieve it using getReader() instead.

    public Cell readInput() {
        try {
            System.out.print("Enter the co-ordinate Seperated by Comma");
            String coOrdinates = getReader().readLine();
            String[] values=coOrdinates.split("\\,");
            return new Cell(Integer.parseInt(values[0]),Integer.parseInt(values[1]));
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return null;
    }
    
  4. In your test class initialize your ConsoleReader as Mockito.spy

    ConsoleReader consoleReader = spy(new ConsoleReader());
    
  5. Mock your getter

    private BufferedReader bufferedReader = mock(BufferedReader.class);
    
    @Before
    public void setUp() {
        doReturn(bufferedReader).when(consoleReader).getReader();
        doCallRealMethod().when(consoleReader).readInput();
    }
    
  6. Define your test:

    @Test
    public void testReadInput() {
        when(bufferedReader.readLine()).thenReturn("123,456");
    
        Cell expectedCell = new Cell(123, 456);
        Cell actualCell = consoleReader.readInput();
    
        assertEquals(expectedCell, actualCell);   
    }
    
ETO
  • 6,970
  • 1
  • 20
  • 37
1

You can use Mockito to mock the BufferedReader, like the example below.

BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
Mockito.when(bufferedReader.readLine()).thenReturn("1", "2", "3");
// You can mock the result based on the type of result you are expecting.
joemokenela
  • 299
  • 1
  • 9