Selenium Framework – Data Driven Testing with Cucumber

In this post i am going to discuss how we can do data driven testing while doing BDD – Cucumber based Framework implementation.

Pre-requisites:

Before you proceed, you will need to know the following

  1. Writing Features
  2. Maven
  3. Cucumber framework
  4. Basic parameterization technique in cucumber feature file

In my application under test, i am building a script to test Account Transfer function

This is how my Maven project structure looked like at the end:

projectStructure

The excel file in which i’ve saved the Test data

excel

My Feature file 

Note that i’ve parameterized the test data such as customer ID, account transfer details etc. as s “row_Index”

Value for the row Index is provided in the Examples. 1 and 2 corresponds to excel row#2 and 3 (row#1 being header row)

These values are picked up by Step Definition class file and available as parameter for all the corresponding annotated functions (@Given, @when etc. wherever applicable. Refer to feature file screenshot below)

What happens next? First take a look at the Feature file screenshot below and then we will proceed to next section

feature

 

So as i said above, row_index value is available as parameter for my stepDefinition class which looks like below:

public class AccountTransfer {

 WebDriver sunViewDriver;
 POMSunViewLoginPage l; 
 POMTreasuryDBPage t;
 POMTransferCenterPage ct;

 public List <hashmap<string,string>&gt; dataSet;

 public AccountTransfer(){

 File file = new File("C:/Selenium/JarFiles/chromedriver.exe");
 System.setProperty("webdriver.chrome.driver", file.getAbsolutePath());
 sunViewDriver = new ChromeDriver();
 sunViewDriver.get("https://wholesaleportal-itca.suntrust.com/SunView/user/login?contextType=external&amp;username=string&amp;initial_command=NONE&amp;password=secure_string&amp;challenge_url=https%3A%2F%2Fwholesaleportal-itca.suntrust.com%2FSunView%2Fuser%2Flogin&amp;request_id=6651191237148972048");

 dataSet = DataHelper.readExcelDatafromFile("C://Selenium//TestData//AccountTransfer.xlsx", "Sheet1");
 }

 @Given("^Login to SunView as \"(.*?)\" customer$")
 public void login_to_SunView_as_customer(String excelDataRow) throws Throwable {

 //access the first hashmap in the List
 int dataRow = Integer.parseInt(excelDataRow)-1;
 l = new POMSunViewLoginPage(sunViewDriver);
 //Make sure that they key name matches with column name you provided on header row in Excel
 l.loginToSunView(dataSet.get(dataRow).get("customerID"), dataSet.get(dataRow).get("userID5x"), dataSet.get(dataRow).get("password5x_SunView"));
 sunViewDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
 }

 @When("^user provides provides account transfer data as in \"(.*?)\"$")
 public void user_provides_provides_account_transfer_data_as_in(String excelDataRow) throws Throwable{

 //access the first hashmap in the List
 int dataRow = Integer.parseInt(excelDataRow)-1;
 t = new POMTreasuryDBPage(sunViewDriver);
 ct = new POMTransferCenterPage(sunViewDriver);

 t.clickOnTransfers_SingleTransfer();
 ct.createSingleTransfer(dataSet.get(dataRow).get("FromAccount"), dataSet.get(dataRow).get("ToAccount"),dataSet.get(dataRow).get("Amount"), dataSet.get(dataRow).get("Date"), dataSet.get(dataRow).get("Frequency"), dataSet.get(dataRow).get("RecurringSchedule"), dataSet.get(dataRow).get("NumberOfPaymentsOption"), dataSet.get(dataRow).get("SendTotalTransfers"), dataSet.get(dataRow).get("EndOnThisDate"), dataSet.get(dataRow).get("Options"), dataSet.get(dataRow).get("Memo"));

 }

 @When("^Submits the transfer$")
 public void submits_the_transfer() throws Throwable {
 ct.PreviewTransfer();

 }

 @Then("^That Transfer should be successful$")
 public void that_Transfer_should_be_successful() throws Throwable {

 ct.validateTransfer();
 ct.searchTransferToVerifySuccessfullSubmit();
 t.clickOnTreasuryDashboard();
 t.logoutOfSunView();
 }
}
 

 

So as you can see in the above code, I have created a List variable that holds hashmaps in it. Then  i am calling a excel reading function by passing it the file location and sheet name as parameters, which is nothing but the location where i’ve saved my Test data excel fie. The List that the function returns is saved in my local List variable.

So now, lets get into the details of excel Reading function and how it is implemented.

In the Data Helper package i’ve a class file in which i have the excel reading function. Step by step details of how it is working given below:

  1. Declared a new List Object that holds a collection of HashMaps
  2. Using the Apache POI functions, I am picking the excel file, navigating to the required sheet
  3. Declared a Variable of type Row called HeaderRow and hardcoded it to point to row#0, i.e the first row of my excel that has header details aka column names
  4. Enter the for loop to iterate the rows
  5. Now, i declared a HashMap object which holds Key and its values in String format
  6. Why declare HashMap object inside the For loop? Because i want every row of excel data to be saved in a unique HashMap objects
  7. Enter the for loop to iterate the column
  8. notice that the “KEY” part of the hashmap always refers to the header row and picks the corresponding column’s cell value
  9. notice that the “VALUE” part of the hashmap refers the current Row- current column (current as in for loop’s iteration)
  10. Exit the Column-Iterating for loop
  11. Add the hashmap into the List object bucket
  12. Repeat the step4 to 11 as many # of times as the # of rows are there in excel file
  13. Exit the Row for loop
  14. Finally, Return the List object

Below is the code:

public class DataHelper {
public static HashMap<String,String> storeValues = new HashMap<String, String>();
public static List<HashMap<String,String>> readExcelDatafromFile(String filePath, String sheetName){

//create Java List to store Hashmaps
List <HashMap<String,String>>excelData = new ArrayList<>();

try{
FileInputStream fs = new FileInputStream(filePath);
XSSFWorkbook wb = new XSSFWorkbook(fs);
XSSFSheet sheet = wb.getSheet("Sheet1");

//catch header row, so that you can use it as Key for your hashmap
Row HeaderRow = sheet.getRow(0);

for(int r = 1; r<=sheet.getPhysicalNumberOfRows();r++){
Row CurrentRow = sheet.getRow(r);
//each row of data is stored in new hashmap
HashMap<String,String> currentRowMap = new HashMap<String,String>();

for(int c=0;c<CurrentRow.getPhysicalNumberOfCells();c++){
Cell CurrentCell = CurrentRow.getCell(c);
System.out.print(CurrentCell.getStringCellValue() + "\t");
currentRowMap.put(HeaderRow.getCell(c).getStringCellValue(),CurrentCell.getStringCellValue());
// i.e hashmap<key, value> = <row(0)column(c), row(1)column(c)>
}
excelData.add(currentRowMap);
}
wb.close();
fs.close();
}
catch(Exception e){
e.printStackTrace();
}

return excelData;

}
}

 

Let me show you pictorially what this hashmaps look like

HASHMAP

And this is how the List Object excelData looks like

HashMap2

So in the below code(extracted from StepDefinition package), I’m essentially using the dataRow variable to access the hashmap#1, 2 etc… And then, .get(“key”) function access the Keys like customerID, UserID etc and fetches its values

@Given("^Login to SunView as \"(.*?)\" customer$")
public void login_to_SunView_as_customer(String excelDataRow) throws Throwable {

//access the first hashmap in the List
int dataRow = Integer.parseInt(excelDataRow)-1;
l = new POMSunViewLoginPage(sunViewDriver);
//Make sure that they key name matches with column name you provided on header row in Excel
l.loginToSunView(dataSet.get(dataRow).get("customerID"), dataSet.get(dataRow).get("userID5x"), 

 

Finally the TestRunner class. I’m not going in detail here. There is hardly any change to this class file. It is a standard one

package testConfig;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith (Cucumber.class)
@CucumberOptions (
features = "src/test/java/Features",
glue = "stepDefinition",
plugin = {
"pretty",
"html:target/cucmber",
}
)
public class AccountTransferTest {

}

 

 

 

Selenium CrossBrowser Testing:One Test Method, DataProvider – Run the test of multiple browsers

This post sequel to my earlier Post.

What different i did this time is – Parameterization of DataProvider.

When i write this post, i didnt come acrosss any option provided by TestNG to parameterize the DataProvider method.

Now you may ask me the question – why parameterize Dataprovider?

When you run the same test case on multiple browsers, you would like to use the different input excels for each different browsers. In my last post, in order to pick and read the relevant file, i was first finding out the calling Test name. Based on the test name, i was passing the corresponding file to the excel reading function.

But i wanted to harness the power of XML and make my dataprovider more flexible. While the XML allows the user to configure and run the same Test case on various browsers based on browser name that is given to it, i was trying to build the same flexibility to my dataProvider also. The dataprovider should not except the file name to be hardcoded in the class. It should pick the file that is fed to it from XML.

Though i couldnt find the direct way of doing it, I implemented in slightly round-about way.

Instead of passing the parameter to the dataprovider method, I passed it to my @BeforeTest Method itself.In that method i captured the value of file name parameter in one of the class variable.

String testName,fileName;

@BeforeTest
@Parameters({"Browser", "filePath"})
public void intiateWebDriver(String Browser,String filePath){
fileName = filePath;

This class variable was then used in dataprovider method.

@DataProvider(name = "dp")
public String[][] readInputData() throws IOException{

String[][] TestData = null;
utilityClass u = new utilityClass();

TestData = u.excelDataReader(fileName);
return TestData;
}

XML file looks like this. Note that i’m passing multiple parameters for each Test.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Default suite" parallel = "tests" thread-count = "10">
	<listeners>
	<listener class-name="org.uncommons.reportng.HTMLReporter"/>
	<listener class-name="org.uncommons.reportng.JUnitXMLReporter"/>
</listeners>
<test name="TestChrome">
<parameter name="Browser" value="chrome" />
<parameter name="filePath" value="C://Selenium//TestData//AccountTransfer.xlsx" />
<classes>
<class name="sunView5xTest.AccountTransferMultiBrowserTest">
</class>
</classes>
</test>
<test name="TestIE">
<parameter name="Browser" value="IE" />
<parameter name ="filePath" value="C://Selenium//TestData//AccountTransferIE.xlsx" />
<classes>
<class name="sunView5xTest.AccountTransferMultiBrowserTest">
</class>
</classes>
</test>
</suite>

 

 

Example of data driven Testing

Image

In this post, i will given an example of data driven test that i carried out on google.com.

I saved a excel with data – Input string for search box & the xpath of the links in search result that i want to click. The above snap shows the excel with data.

package DataDrivePackage;
import com.thoughtworks.selenium.*;

import junit.framework.TestCase;
import org.junit.AfterClass;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.server.SeleniumServer;
import org.testng.annotations.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

import jxl.*;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

public class googleTest {
        
    WebDriver d    = new InternetExplorerDriver ();

    @BeforeClass
    public void envSetup()throws Exception
    {
        d.get(“http://www.google.co.in/&#8221;);
        System.out.println(“opened the browser”);
    }
    
    
    public void checkUrl()throws Exception
    {
        if (d.getCurrentUrl() != “http://www.google.co.in/&#8221; )
        {
            System.out.println(“yes google is not on”);
            d.get(“http://www.google.co.in/&#8221;);
            d.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        }    
    }
    
    
    @Test (dataProvider = “dp”)
    public void gTest (String searchString, String clickLink)throws Exception
    {
        System.out.println(searchString+” “+ clickLink);
        d.findElement(By.xpath(“//INPUT[@id=’gbqfq’]”)). sendKeys (searchString);
        WebElement e = d.findElement(By.xpath(“//INPUT[@id=’gbqfq’]”));
        e.submit();
        d.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        d.findElement (By.xpath(clickLink)).click();
        checkUrl();
    }
    
    
    @DataProvider(name = “dp”)
    public Object[][] sendData ()throws Exception
    {
       Object[][] retData = getArrayTable (“C:\\selDataFolder\\googleTest.xls”);
       return (retData);
    }

    public static String[][] getArrayTable (String xlPath) throws Exception
    {    
        int r = 0, c =0;
        
        InputStream inputStream = new FileInputStream(xlPath);
        POIFSFileSystem fileSystem = new POIFSFileSystem (inputStream);
        HSSFWorkbook workBook = new HSSFWorkbook (fileSystem);
            
        HSSFSheet sheet = workBook.getSheetAt(0);
        Iterator<Row> rows = sheet.rowIterator();
        
        int totalRows = sheet.getPhysicalNumberOfRows();
        HSSFRow row1 = sheet.getRow(1);
        int totalCols = row1.getLastCellNum();
        String[][] tabArray = new String[totalRows][totalCols];
    
        while (rows.hasNext())
        {
            Row row = rows.next();
            
            Iterator<Cell> cells = row.cellIterator();
            while (cells.hasNext())
            {
                Cell cell = cells.next ();
                tabArray[r][c] = cell.getStringCellValue ();
                ++c;
            }
            
            c=0;
            ++r;
        }
        return tabArray;
    }
}

Explaination

1. I create a input stream of type file inputstream.

2. Created a POIFSFileSystem, taking this file input stream as parametr.

3. Created a HSSF workbook, to access the excel.

4. Created a Iterator of Row class type. Using this iterator, i can get a collection of rows in the sheet with the pointer at row beginning.

5. using hasNext() method, i move thru the rows.

6. I create a object of type Row class to store the pointer to the next row as i iterate.

7. Similarly, i iterate thru the cells in the same way as i explainted for the rows above.

8. Store the result in a array and return it.