TestNG Dataprovider Need help to run @Test individually based on test data

1.2k views Asked by At

I'm working on Rest API testing (POST method) for which I'm reading json data from spreadsheet using TestNg Dataprovider. My Dataprovider returns HashMap with key: Integer Row_Number and value: ArrayList (String) of test data. Below is the sample map returned by DataProvider. {0=[Sample1, Name1, [email protected], (000) 111-1111], 1=[Sample2, Name2, [email protected], (000) 111-1112]}

My current implementation of Dataprovider is,

@DataProvider
public Object[][] JSONBODY()
{
String test_data = "json_data";
int row = ExcelUtils.getRowNum(test_data, col_num);
int total_col = ExcelUtils.getLastColumnNumber(row);
Map<Integer, ArrayList<String>> map = ExcelUtils.getTableArray(spreadsheet_location,test_data,total_col);
return new Object[][] { { map } };
}

getTableArray implementation

public static Map<Integer, ArrayList<String>> getTableArray(String FilePath, String testdata, int total_Col) throws Exception {
Map<Integer, ArrayList<String>> map = new HashMap<Integer, ArrayList<String>>();
ArrayList<Integer> iTestCaseRow = null;
try
{
    FileInputStream ExcelFile = new FileInputStream(FilePath);
    ExcelWBook = new XSSFWorkbook(ExcelFile);
    ExcelWSheet = ExcelWBook.getSheet(SheetName);
    int startCol = 1;
    iTestCaseRow = ExcelUtils.getRowContains(testdata ,col_num); // getRowContains returns list of row numbers for value in testdata.
    int totalRows = iTestCaseRow.size();
    int totalCols = total_Col;
    for(int i=0; i<totalRows;i++)
    {
        ArrayList<String> str = new ArrayList<String>();
        for (int j=startCol;j<=totalCols;j++)
        {
            str.add (ExcelUtils.getCellData(iTestCaseRow.get(i),j));  
        }
        map.put(iTestCaseRow.get(i), str);
    }
    return map;
}
}

Test Method

@Test(dataProvider = "JSONBODY")
public void TestMethod(Map<Integer, ArrayList<String>> map) throws Exception {
try
{
Log.startTestCase("Start executing Test Case");
Set<Integer> key = map.keySet();
for(Integer row: key)
{
    SamplePojo pojo = new SamplePojo();
    ArrayList<String> data = map.get(row);
    pojo.setFirstName(data.get(0));
    pojo.setLastName(data.get(1));
    pojo.setEmail(data.get(2));
    pojo.setPhone(data.get(3));
    Response res = RestAssured.given().contentType(ContentType).body(pojo).when().post(POST_URL);
    Log.info(res.asString());
    Assert.assertTrue(res.getStatusCode() == 200 , "Test Case failed");
}
}
}

Spreadsheet Test Data is, Spreadsheet Data

When I execute my @Test method, TestNG executes as one method instead of two as I have 2 rows of test data(value: json_data) in the spreadsheet. Kindly help me in running the Test method individually for each key:value pair. Thanks in advance!

2

There are 2 answers

0
Krishnan Mahadevan On BEST ANSWER

The problem is in your data provider. After you obtain your map, you need to translate that map such that every entry in it is now part of the 2D Object array. In your case, you have basically just added that entire map as one single data item in the 2D object array.

Please see below for a full fledged example that shows what I am referring to. For the sake of convenience I have basically excluded the excel spreadsheet reading logic etc.,

import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestClass {

    @Test(dataProvider = "dp")
    public void testMethod(Map<Integer, List<String>> data) {
        Assert.assertTrue(data.size() == 1);
        List<String> values = data.values().iterator().next();
        System.err.println("Values = " + values);
    }


    @DataProvider(name = "dp")
    public Object[][] getData() {
        Map<Integer, List<String>> data = getTableArray();
        //Transform the Map into a 2D array such that every key/value
        //pair in the map becomes one element in the 2D array
        int size = data.size();
        Object[][] dataToUse = new Object[size][1];
        int i = 0;
        for (Map.Entry<Integer, List<String>> entry : data.entrySet()) {
            Map<Integer, List<String>> localMap = new HashMap<>();
            localMap.put(entry.getKey(), entry.getValue());
            dataToUse[i++] = new Object[]{localMap};
        }
        return dataToUse;
    }

    static Map<Integer, List<String>> getTableArray() {
        Map<Integer, List<String>> data = new HashMap<>();
        data.put(1, Arrays.asList("Sample1", "Name1", "[email protected]", "(000) 111-1111"));
        data.put(2, Arrays.asList("Sample2", "Name2", "[email protected]", "(000) 111-1112"));
        data.put(3, Arrays.asList("Sample3", "Name3", "[email protected]", "(000) 111-1113"));
        return data;
    }
}

Here's the output

Values = [Sample1, Name1, [email protected], (000) 111-1111]
Values = [Sample2, Name2, [email protected], (000) 111-1112]
Values = [Sample3, Name3, [email protected], (000) 111-1113]

===============================================
Default Suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================
0
niharika_neo On

Two options:

Map<Integer, ArrayList<String>> map = ExcelUtils.getTableArray(spreadsheet_location,test_data,total_col);

Object[][] dataToBeReturned = new Object[map.size()][];

//Loop through map and build your array..code not tested..something to the effect
for(Entry<Integer, Arra..> datum : map.entrySet()) {
 dataToBeReturned[i++] = new Object[] {datum.getKey(), datum.getValue()}
}

return dataToBeReturned;

or in your excelreader itself, since you are in any case looping through the data, either put it in an array instead of map - something like

    instead of map.put(iTestCaseRow.get(i), str);
use dataToBeReturned[i++] = new Object[] {iTestCaseRow.get(i), str}