Home > Enterprise >  JUnit : Unit Test for abstract class in a Spring Boot app?
JUnit : Unit Test for abstract class in a Spring Boot app?

Time:11-28

In my Java (Spring Boot) app, I am trying to test the following method using JUnit5 and Mockito:

public abstract class CsvService<T extends CsvBean> {

    public List<T> readFromCsv(Class<T> type, CsvToBeanFilter filter) {
        List<T> data = new ArrayList<>();

        try {
            Resource resource = new ClassPathResource("data/"   getFileName());
            Reader reader = new FileReader(resource.getFile());

            ColumnPositionMappingStrategy<T> strategy = 
                new ColumnPositionMappingStrategy<>();
            strategy.setType(type);
            strategy.setColumnMapping(getColumns());
            
            CsvToBean<T> csvToBean = new CsvToBeanBuilder<T>(reader)                    
                    .withFilter(filter)
                    .build();

            data = getData(csvToBean);
            reader.close();

        } catch (IOException ex) {
            log.error(FILE_READ_ERROR, ex);
            ex.printStackTrace();
        }
        return data;
    }

    protected abstract String getFileName();

    protected abstract String[] getColumns();

    protected abstract List<T> getData(CsvToBean<T> csvToBean);
}

I already wrote Unit Test for the method implementations of the abstract methods (getData(), etc.), but I also want to write Unit Test for this readFromCsv() method.

@Service
public class AirportService extends CsvService<Airport> {

    // code omitted

    @Override
    protected List<Airport> getData(CsvToBean<Airport> csvToBean) {
        List<Airport> airports = new ArrayList<>();

        for (Airport bean : csvToBean) {
            Airport airport = new Airport(
                    bean.getId()
            );
            airports.add(airport);
        }
        return airports;
    }
}

Here is my Unit Test:

@ExtendWith(MockitoExtension.class)
class CsvServiceTest {

    private CsvService service;

    @Mock
    private AirportService airportService;

    @Mock
    private CsvToBean<Airport> csvToBean;

    @Mock
    private CsvToBeanFilter filter;

    @BeforeEach
    void setup() {
        service = new AirportService();
    }


    @Test
    void test() {
        csvToBean.setFilter(filter);

        Airport airport = new Airport(101, "DK");
        when(filter.allowLine((String[]) any())).thenReturn(true);
        when(csvToBean.iterator())
            .thenReturn(new ArrayIterator<>(new Airport[]{airport}));

        List<Airport> result = service.readFromCsv(Airport.class, filter);
        
        // assertions
    }
}

But the test is always read the CSV file as it retrieved via getFileName() method (the file in the project). But I want to mock it and read the provided airport data via stub. So, how can I make this unit test properly testing this CSV reader method?

CodePudding user response:

Either (1) create a Spy instead of the AirportService and mock the getFileName() method:

service = Mockito.spy(new AirportService());

and then mock the desired method:

Mockito.doReturn((/* your value */)).when(service).getFileName();

or (2) create yet another class, this time extending the AirportService; there you can implement the getFileName so it returns your mock file name.

  • Related