Search code examples
javacollectionstestngtestng-dataprovider

Iterating over a CSV file within a TestNG DataProvider


I'm a little confused as to how best to implement a simple DataProvider, having not done so before.

I have a very simple comma delimited .csv file:

978KAL,625JBH,876SSH,452GSH

I simply need to read it in and iterate over the records, running the same test for each record until done.

My code so far:

String csvFile = "src/test/resources/registrationsData.csv";
    BufferedReader br = null;
    String line = "";
    String cvsSplitBy = ",";


    @DataProvider(name="getRegistrations")
    private Object[] getCSVTestData() {
        Object [] registrationsObject;
        try {

            br = new BufferedReader(new FileReader(csvFile));
            while ((line = br.readLine()) != null) {

                // use comma as separator
                String [] registrations = line.split(cvsSplitBy);

                System.out.println( registrations[0] + "," + registrations[1]);

            }

        } catch//File not found & IOException handling here
        registrationsObject = new Object[][]{registrations};
        return registrationsObject;
    }



    @Test(dataProvider = "getRegistrations")
    public void getRegistrations(String registration){

        Object[] objRegArray =  getCSVTestData();

        for(int i=0; objRegArray.length>i; i++){
        //run tests for every record in the array (csv file)
    }
 }

I know that I need to use an Object array return type for the Data Provider method.

I'm unclear as to how (and/or the best way) to retrieve each record from the objRegArray object.

This is a basic Collections question I guess; can anyone point me the right way?


Solution

  • Check this code with my explanation below:

    package click.webelement.testng;
    
    import org.testng.annotations.DataProvider;
    import org.testng.annotations.Test;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.util.Iterator;
    import java.util.Scanner;
    
    public class OneLineCSV {
    
        final static String CSV_FILE = "/path_to_file/oneline.csv";
        final static String DELIMETER = ",";
    
        @DataProvider(name = "test")
        public Iterator<Object[]> testDP(){
            try {
                Scanner scanner = new Scanner(new File(CSV_FILE)).useDelimiter(DELIMETER);
                return new Iterator<Object[]>() {
                    @Override
                    public boolean hasNext() {
                        return scanner.hasNext();
                    }
                    @Override
                    public Object[] next() {
                        return new Object[]{scanner.next()};
                    }
                };
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        @Test(dataProvider = "test")
        public void testOneLineCSV(String value){
            System.out.println(value);
        }
    
    }
    

    So I would use Scanner class hence it has the convenient facility to parse a string into tokens.

    I would also use the capability to return Iterator<Object[]> in your data provider since Scanner is designed in that way. You simply wrap it with new Iterator that converts String that is returned by Scanner.next() to new Object[]{scanner.next}.

    Using Iterator with Scanner is really more comfortable since you may not know how many values you will have to provide. So you shouldn't care of defining array size.