Skip to content
Advertisement

Java how to test correctly mocked instances of POI Row and Cell when use iterator forEach()

Given this code:

protected Sheet getSheet(String pathName, int sheetNumber) throws IOException {
    File file = new File(pathName);
    Workbook workbook = WorkbookFactory.create(file);
    return workbook.getSheetAt(sheetNumber);
}

public List<String> getRowAsString(String pathName, int rowNumber) throws IOException {
    Sheet sheet = getSheet(pathName, 0);
    Row row  = sheet.getRow(rowNumber);
    List<String> cellsString = new ArrayList<>();
    for (int i = 0; i < row.getLastCellNum(); i ++) {
        cellsString.add(row.getCell(i).getStringCellValue());
    }

    return cellsString;
}

I can test it with this:

@Before
public void init() throws IOException {
    when(workbookMock.getSheetAt(anyInt())).thenReturn(sheetMock);
    PowerMockito.mockStatic(WorkbookFactory.class);
    when(WorkbookFactory.create((File) any())).thenReturn(workbookMock);
}

@Test
public void should_return_wanted_row_as_string() throws IOException {
    Row rowMock = mock(Row.class);
    Cell cellMOck1 = mock(Cell.class);
    when(cellMOck1.getStringCellValue()).thenReturn("Valor1");
    Cell cellMOck2 = mock(Cell.class);
    when(cellMOck2.getStringCellValue()).thenReturn("Valor2");
    when(rowMock.getCell(0)).thenReturn(cellMOck1);
    when(rowMock.getCell(1)).thenReturn(cellMOck2);
    when(sheetMock.getRow(anyInt())).thenReturn(rowMock);
    when(rowMock.getLastCellNum()).thenReturn((short) 2);

    List<String> expected = List.of("Valor1", "Valor2");
    List<String> result = sut.getRowAsString("/", 0);

    assertEquals(expected, result);
}

But, if I want to use forEach() instead of for loop in getRowAsString() method, like this:

public List<String> getRowAsString(String pathName, int rowNumber) throws IOException {
    Sheet sheet = getSheet(pathName, 0);
    Row row  = sheet.getRow(rowNumber);
    List<String> cellsString = new ArrayList<>();
    row.forEach(cell -> {
        cellsString.add(cell.getStringCellValue());
    });

    return cellsString;
}

The test doesn’t work because when use stream.forEach() the code is not calling method getCell(index).

How should I test the method to be able to use forEach() instead of traditional for loop?

Advertisement

Answer

Yes, I can create a real instance of workbook using, for example, XSSFWorkbook class.

I was trying wrong to do something like this:

Workbook workbook = new XSSFWorkbook();
Sheet sheet = new XSSFSheet();
workbook.setSheet(sheet);

No problem with XSSFWorkbook, but XSSFSheet has protected access and, obviously, I can’t create an instance of it.

The correct way is:

Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet();
Row row = sheet.createRow();
Cell cell = row.createCell();
...

I did not know that way of working with sheets and I was trying to inject by the classic way.

Advertisement