Overview
Cucumber is Behavioral Driven Development Framework that allows to develop simple text based executable test scenarios. If you have worked with Cucumber BDD, then you know it is sometimes bit difficult to create readable yet functional automated tests. For example, testing with multiple datasets. In this blog, let us have a closer look at the Java Cucumber binding which is Data Tables that helps to write test scenarios with various test data.
Data Tables
Data Table is a data structure provided by Cucumber. It is a bridge which passes values from the feature files to the parameters of the Step Definitions. It can handle large amounts of data and can be passed as one-dimensional, two-dimensional data and in the form of key-value pair.
Data tables are often misunderstood with Example tables or Scenario tables which are used for entire scenarios. So, let us understand these two methods.
Scenario Outline:
· It runs for the whole test scenario.
· Example keyword is used at the end of the Scenario to define the test data.
· The entire test is run for the number of times equal to the number of data entries in the test set.
Example of Scenario Outline
Feature: Login Test
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 |
| Employee_1 | Welc@345 |
| Employee_2 | Test@542 |
Step Definition
@When("^User enters \"(.*)\" and \"(.*)\"$")
public void user_enters_UserName_and_Password(String username, String password) throws Throwable {
driver.findElement(By.id("Username")).sendKeys(username);
driver.findElement(By.id("Password")).sendKeys(password);
//driver.findElement(By.id("Login")).click();
}
In this example, the scenario will run two times, passing in one row at each time.
Data Tables:
· It will work only for that single step under which the test data is defined.
· It is not required to use any Keyword to define the test data.
· The entire test will run once and only the step definition with test data will iterate equal to data entries. To integrate such way, a separate code is written which runs single or multiple times.
Implementation of Data Tables
Let us understand how to incorporate the Data tables in the automation code with example.
Pre-Requisite:
Cucumber
Java – 11
Selenium
Junit (You can use TestNG also)
Cucumber JUnit (If using TestNG, then replace this with Cucumber TestNG)
Project Structure:
Data tables from Gherkin can be accessed by using the DataTable object as the last parameter in a Step Definition. This conversion can be done either by Cucumber or manually. Depending on the data, we can use List and Map collections such as
Table into List<List<String>> (List of a List of Strings)
Example:
| FirstName | LastName | Age |
| Geeta | Thomas | 40 |
| Lisa | Red | 34 |
| Mitchell | Dunphy | 36 |
java type: List<List<String>>
The normal representation of list of a list of strings is shown below.
[
[ "firstName", "LastName", "Age” ],
[ "Geeta", "Thomas", "40" ],
[ "Lisa", "Red", "34" ],
[ "Mitchell", "Dunphy", "36" ]
]
Table into List<Map<String, String>> (List of Maps)
Example:
java type: List<Map<String, String>>
The normal representation of list of maps is shown below.
[
{ "firstName": "Geeta", "lastName": "Thomas", "age": "40" },
{ "firstName": "Lisa", "lastName": "Red", "age": "34" },
{ "firstName": "Mitchell", "lastName": "Dunphy", "age": "36" }
]
Table into Map<String, String>
Example:
Table where first column is key as shown below
| WA | Washington |
| IL | Illinois |
java type: Map<String, String>
TO convert the table into a single map
{
"WA": "Washington",
"IL": "Illinois"
}
Table into Map<String, List<String>> (Map uses list as its value)
A table with multiple column values per key.
| EmpID01 | Geeta | 02 |
| EmpID02 | Lisa | 05 |
java type: Map<String, List<String>>
{
"EmpID01": ["Geeta","02"],
"EmpUD02": ["Lisa","05"]
}
Let us code Data table in Cucumber using Java.
Data tables without Headers Example:
Suppose we want to test Login page of the application. We will pass the test data with step definition.
Feature: Login with valid credentials
Scenario: Successful login with valid credentials
Given User is on the Login Page
When User enters Credentials
| Sharon2023 | Welcome@2023 |
Then User should see the LMS Home page
Here we are passing tables as arguments to step definition instead of using Example keyword.
Below is the step definition implementation:
import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
public class DataTableDefinitions {
WebDriver driver;
@Before
public void setup() {
System.setProperty("webdriver.chrome.driver","src/test/resources/Drives/chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
@Given("User is on the Login page")
public void userOnHomePage() {
driver.get("https://lms-frontend-phase2.herokuapp.com/login ");
}
@When("User enters valid credentials")
public void entersValidCredential(DataTable dataTable) throws InterruptedException{
System.out.println("Credentials Entered");
List<String> LoginForm = dataTable.asList();
String userName = LoginForm.get(0);
String passWord = LoginForm.get(1);
driver.findElement(By.name("Username")).sendKeys(userName);
driver.findElement(By.name("Password")).sendKeys(passWord);
driver.findElement(By.id("LoginBtn")).submit();
}
@Then("User should see the LMS Home page ")
public void successfulLogin() throws InterruptedException {
String Homepage = driver.findElement(By.id("welcome")).getText();
System.out.println("Homepage :" + newPageText);
assertThat(Homepage, containsString("Welcome"));
}
@After
public void teardown(){
driver.close();
}
}
In this example, a List<List<String>> is used so we can get the data from DataTable. As there is no header in the table, we can get the data from index 0. asLists() method is used which supplies a String class argument and this argument also tells asLists() method what is the data type of each element.
Data Tables with Multiple Test Data using Maps
In this example, let us take multiple entries of Username and Password with Headers.
Feature: Login with valid credentials
Scenario: Successful login with valid credentials
Given User is on the Login Page
When User clicks the Login button after entering valid username and password
| Username | Password |
| Sharon2023 | Welc@2023 |
| Alex123 | Welcome@2022 |
| Shai23 | cAme@2023 |
Then User should see the LMS Home page
In Step definition, only @when method changes rest will be the same as mentioned above.
@When("User enters valid credentials")
public void entersValidCredential(DataTable dataTable) throws InterruptedException
{
List<Map<String, String>> user = userTable.asMaps(String.class, String.class);
for (Map<String, String> form : user) {
String userName = form.get("Username");
System.out.println("Username :" + userName);
driver.findElement(By.name("Username")).sendKeys(userName);
String passWord = form.get("Password");
System.out.println("Password :" + passWord);
driver.findElement(By.name("Password")).sendKeys(passWord);
driver.findElement(By.id("LoginBtn")).submit();
}
Here, although a list containing each row is created, Cucumber maps the column heading to each column value. This process is repeated for each subsequent row. To achieve this, asMaps(String, String) method is used which takes two arguments. First argument denotes the data type of the headers (keys) which is String. The second argument also denotes String as the data type because values are all String.
Conclusion
In this blog, we saw few examples of how we can add test data to feature files using Data Tables and Scenario Outline. Certainly, the Data Tables can be used to specify the complex data in more readable manner. We learnt, Cucumber automatically converts the Data Tables into particular data structures and from then we can iterate over the data to process effectively. Data tables can save the iterations over the specifications and can iterate the data only over the step definitions.