Maps in Data Tables

In the previous chapter of Data Tables in Cucumber, we consider a very simple example of passing UserName and Password in the step. Let’s take a little complex scenario where  a good amount of data is required to pass in the step. Or what is there are multiple columns of test data is present. How would you handle it? The answer is to make a Use of Maps in Data Tables.

Maps in Data Tables

Maps in Data Tables can be used if different ways. Headers can also be defined for the data tables. A same step can be executed multiple times with different set of test data using Maps.

Maps in Data Tables with Header

In the previous chapter of Data Tables in Cucumber we pass Username & Password without Header, due to which the test was not much readable. What if there will be many columns. The basic funda of BDD test is to make the Test in Business readable format, so that business users can understand it easily. Setting Header in Test data is not a difficult task in Cucumber. take a look at a below Scenario.
Feature File Scenario
Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters Credentials to LogIn
| Username   | Password |
    | testuser_1 | Test@153 |
Then Message displayed Login Successfully
The implementation of the above step will be like this:
@When("^User enters Credentials to LogIn$")
public void user_enters_testuser_and_Test(DataTable usercredentials) throws Throwable {

//Write the code to handle Data Table
List<Map<String,String>> data = usercredentials.asMaps(String.class,String.class);
driver.findElement(By.id("log")).sendKeys(data.get(0).get("Username")); 
   driver.findElement(By.id("pwd")).sendKeys(data.get(0).get("Password"));
   driver.findElement(By.id("login")).click();
           }

Maps in Data Tables with Multiple Test Data

In this test we will pass Username and Password two times to the test step. So our test should enter Username & Password once, click on LogIn button and repeat the same steps again.
Feature File Scenario
Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters Credentials to LogIn
| Username   | Password |
    | testuser_1 | Test@153 |
    | testuser_2 | Test@154 |
Then Message displayed Login Successfully
The implementation of the above step will be like this:
@When("^User enters Credentials to LogIn$")
public void user_enters_testuser_and_Test(DataTable usercredentials) throws Throwable {

//Write the code to handle Data Table
for (Map<String, String> data : usercredentials.asMaps(String.class, String.class)) {
driver.findElement(By.id("log")).sendKeys(data.get("Username")); 
   driver.findElement(By.id("pwd")).sendKeys(data.get("Password"));
   driver.findElement(By.id("login")).click();
}

}

Map Data Tables to Class Objects

Luckily there are easier ways to access your data than DataTable. For instance you can create a Class-Object and have Cucumber map the data in a table to a list of these.
Feature File Scenario
Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters Credentials to LogIn
| Username   | Password |
    | testuser_1 | Test@153 |
    | testuser_2 | Test@154 |
Then Message displayed Login Successfully
The implementation of the above step will be like this:
@When("^User enters Credentials to LogIn$")
public void user_enters_testuser_and_Test(List<Credentials>  usercredentials) throws Throwable {

//Write the code to handle Data Table
for (Credentials credentials : usercredentials) {
driver.findElement(By.id("log")).sendKeys(credentials.getUsername()); 
   driver.findElement(By.id("pwd")).sendKeys(credentials.getPassword());
   driver.findElement(By.id("login")).click();
}
}
Class Credentials
package stepDefinition;

public class Credentials {
private String username;
private String password;

public String getUsername() {
        return username;
    }
public String getPassword() {
        return password;
    }
}

Data Tables in Cucumber

Data Tables in Cucumber are quite interesting and can be used in many ways. DataTables are also used to handle large amount of data. They are quite powerful but not the most intuitive as you either need to deal with a list of maps or a map of lists. Most of the people gets confused with Data tables & Scenario outline, but these two works completely differently.

Difference between Scenario Outline & Data Table

Scenario Outline:
  • This uses Example keyword to define the test data for the Scenario
  • This works for the whole test
  • Cucumber automatically run the complete test the number of times equal to the number of data in the Test Set
Test Data:
  • No keyword is used to define the test data
  • This works only for the single step, below which it is defined
  • A separate code is need to understand the test data and then it can be run single or multiple times but again just for the single step, not for the complete test

As I said above, that the Data Tables can be used in many ways because it has provided many different methods to use. Let’s just go through few most popular methods. I will choose a simple scenario to illustrate the working of the Data Table but we will make effective use of this when we will do Cucumber Framework in the next series of this Cucumber Tutorial.


Data Tables in Cucumber

In this example, we will pass the test data using data table and handle it with using Raw() method.
Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters Credentials to LogIn
    | testuser_1 | Test@153 |
Then Message displayed Login Successfully
The complete scenario is same as what we have done earlier. But the only difference is in this, we are not passing parameters in the step line and even we are not using Examples test data. We declared the data under the step only. So we are using Tables as arguments to Steps.
If you run the above scenario without implementing the step, you would get the following error in the Eclipse console window.
DataTable_Cucumber_1
Copy the above hint in the Step Definition file and complete the implementation.
The implementation of the above step will belike this:
@When("^User enters Credentials to LogIn$")
public void user_enters_testuser__and_Test(DataTable usercredentials) throws Throwable {

//Write the code to handle Data Table
List<List<String>> data = usercredentials.raw();

//This is to get the first data of the set (First Row + First Column)
driver.findElement(By.id("log")).sendKeys(data.get(0).get(0)); 

//This is to get the first data of the set (First Row + Second Column)
   driver.findElement(By.id("pwd")).sendKeys(data.get(0).get(1));

   driver.findElement(By.id("login")).click();
}

The complete test Implementation

Test Runner Class
package cucumberTest;

import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(
features = "Feature"
,glue={"stepDefinition"}
)

public class TestRunner {

}
Feature File
Feature: Login Action

Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters Credentials to LogIn
    | testuser_1 | Test@153 |
Then Message displayed Login Successfully

Scenario: Successful LogOut
When User LogOut from the Application
Then Message displayed LogOut Successfully
Step Definition
package stepDefinition;

import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import cucumber.api.DataTable;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class Test_Steps {
public static WebDriver driver;
@Given("^User is on Home Page$")
public void user_is_on_Home_Page() throws Throwable {
driver = new FirefoxDriver();
   driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
   driver.get("http://www.store.demoqa.com");
}

@When("^User Navigate to LogIn Page$")
public void user_Navigate_to_LogIn_Page() throws Throwable {
driver.findElement(By.xpath(".//*[@id='account']/a")).click();
}

@When("^User enters Credentials to LogIn$")
public void user_enters_testuser__and_Test(DataTable usercredentials) throws Throwable {
List<List<String>> data = usercredentials.raw();
driver.findElement(By.id("log")).sendKeys(data.get(0).get(0)); 
   driver.findElement(By.id("pwd")).sendKeys(data.get(0).get(1));
   driver.findElement(By.id("login")).click();
}

@Then("^Message displayed Login Successfully$")
public void message_displayed_Login_Successfully() throws Throwable {
System.out.println("Login Successfully");
}

@When("^User LogOut from the Application$")
public void user_LogOut_from_the_Application() throws Throwable {
driver.findElement (By.xpath(".//*[@id='account_logout']/a")).click();
}

@Then("^Message displayed LogOut Successfully$")
public void message_displayed_LogOut_Successfully() throws Throwable {
System.out.println("LogOut Successfully");
}
}
Project Explorer
DataTable_Cucumber_1

Run the test by Right Click on TestRunner class and Click Run As  > JUnit Test Application. you will notice that Cucumber will automatically figure out, what to provide in the Username and Password field.
In the next chapter of Data Tables in Cucumber using Maps, we will handle little complex data .

Data Driven Testing Using Examples Keyword

In the last chapter of Parameterization in Cucumber, we learned how to parameterize data. But with that trick only limited functionality can be achieved of Data Driven. As the test can be run multiple times. But by now that you know the anatomy of a Data-Driven test, here’s a trick that simplifies the process of Data Driven testing using CucumberCucumber inherently supports Data Driven testing by the use of the Scenario Outline and Examples section. It is with these keywords that Cucumber allows for easy Data Driven testing to be completed where no changes need to be made to the Java file. In this tutorial we learn, How to Implement Scenario Outline in Data Driven testing using Examples Keyword?
Example keyword can only be used with the Scenario Outline Keyword.
  • Scenario Outline – This is used to run the same scenario for 2 or more different set of test data. E.g. In our scenario, if you want to register another user you can data drive the same scenario twice.
  • Examples – All scenario outlines have to be followed with the Examples section. This contains the data that has to be passed on to the scenario.

Data Driven Testing Using Examples Keyword

If you understood the concept of Parameterization in Cucumber, you would find this one very easy. In this tutorial as well I am taking the same LogIn test scenario.
1) Enter the Example Data just below the LogIn Scenario of the Feature File.
Examples:
          | username  | password  |
          | testuser_1 | Test@153 |
          | testuser_2 | Test@153 |

Note: The table must have a header row corresponding to the variables in the Scenario Outline steps.
The Examples section is a table where each argument variable represents a column in the table, separated by “|”. Each line below the header represents an individual run of the test case with the respective data. As a result if there are 3 lines below the header in the Examples table, the script will run 3 times with its respective data.

2) Need to update the Statement in the feature file, which tells Cucumber to enter username & Password.
And User enters <username> and <password>
Cucumber understands the above statement syntax and look for the ExamplesKeyword in the test to read the Test Data.
The complete code will look like this:
Feature: Login Action

Scenario Outline: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters "<username>" and "<password>"
Then Message displayed Login Successfully
Examples:
    | username   | password |
    | testuser_1 | Test@153 |
    | testuser_2 | Test@153 |
3) There are no changes in TestRunner class.
package cucumberTest;

import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(
features = "Feature"
,glue={"stepDefinition"}
)

public class TestRunner {

}
4) There are no changes in Test_Steps file from the previous chapter.
package stepDefinition;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class Test_Steps {
public static WebDriver driver;
@Given("^User is on Home Page$")
public void user_is_on_Home_Page() throws Throwable {
driver = new FirefoxDriver();
   driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
   driver.get("http://www.store.demoqa.com");
}

@When("^User Navigate to LogIn Page$")
public void user_Navigate_to_LogIn_Page() throws Throwable {
driver.findElement(By.xpath(".//*[@id='account']/a")).click();
}

@When("^User enters \"(.*)\" and \"(.*)\"$")
public void user_enters_UserName_and_Password(String username, String password) throws Throwable {
driver.findElement(By.id("log")).sendKeys(username);  
   driver.findElement(By.id("pwd")).sendKeys(password);
   //driver.findElement(By.id("login")).click();
}

@Then("^Message displayed Login Successfully$")
public void message_displayed_Login_Successfully() throws Throwable {
System.out.println("Login Successfully");
}

@When("^User LogOut from the Application$")
public void user_LogOut_from_the_Application() throws Throwable {
driver.findElement (By.xpath(".//*[@id='account_logout']/a")).click();
}

@Then("^Message displayed LogOut Successfully$")
public void message_displayed_LogOut_Successfully() throws Throwable {
System.out.println("LogOut Successfully");
}

}
5) Run the test by Right Click on TestRunner class and Click Run As  > JUnit Test Application.
This takes the parameterization one step further: now our scenario has “variables” and they get filled in by the values in each row. To be clear: by defining this, the scenario will run two times, passing in one row at a time. This makes it very easy to define a lot of examples, edge cases and special outcomes.  Instead of hardcoding the test data, variables are defined in the Examples section and used in Scenario Outline section.
Note: Please create your own username & password for the test, if you supply wrong UserName & Password 3 times, your IP will get blocked.