Cucumber data table – convert a two column table to a Map

Introduction

In this post we will see an example on cucumber data table – convert a two column table to a Map. Cucumber is a tool for running automated acceptance tests written in a behavior-driven development (BDD) style. Cucumber is written in the Ruby programming language. Cucumber projects are available for other platforms beyond Ruby.

Cucumber works with Ruby, Java, .NET, Flex or web applications written in any language. It has been translated to over 40 spoken languages. – http://cukes.info/

The language that Cucumber understands is called Gherkin.

While Cucumber can be thought of as a “testing” tool, the intent of the tool is to support BDD. This means that the “tests” (plain text feature descriptions with scenarios) are typically written before anything else and verified by business analysts, domain experts, etc. non technical stakeholders. The production code is then written outside-in, to make the stories pass.

Cucumber itself is written in Ruby, but it can be used to “test” code written in Ruby or other languages including but not limited to Java, C# and Python.

Recommended reading: Posts on Cucumber with Java

Prerequisites

Eclipse, Java 1.8, Cucumber 1.2.5, Junit 4.12, Gradle 4.10.2 or Maven 3.6.6

Example with Source Code

In this example I will show you how we can use cucumber’s nice feature that helps us to use tables in our scenarios. The table can easily be converted to a list or map that we can use in our step.

Creating Project

Create a gradle based project in Eclipse. The project structure would look similar to the below image:

cucumber data table - convert a two column table to a map

Updating Build Script

Update the build.gradle script in order to add few dependencies for our application.

apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
	mavenLocal()
    mavenCentral()
}
dependencies {
	compile('info.cukes:cucumber-java:1.2.5')
	compile('info.cukes:cucumber-junit:1.2.5')
	compile('junit:junit:4.12')
}

If you want to use maven based project then you can use below pom file:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.roytuts</groupId>
    <artifactId>java-cucumber</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk.version>1.8</jdk.version>
        <junit.version>4.12</junit.version>
        <cucumber.version>1.2.5</cucumber.version>
    </properties>
    <dependencies>
        <!-- cucumber -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Creating Test Resources

Create src/test/resources folder, if it already does not exist, for putting the resource files.

Do right-click on the project and go New -> Source Folder. Give Folder name: as src/test/resources and click on Finish button.

Creating Feature File

Create a feature files called employeelist.feature under src/test/resources/cuke/flow/feature with the below content:

Feature: An organization recruits few more employees
"""
The organization got more projects from existing or new clients, so it has decided
to recruit more employees to provide services to its customers
"""
Scenario: An organization recruits employees based on designations
    Given an organization has employees
        |      PM     |     5     |
        |   Sr. Dev   |   200     |
        |   Jr. Dev   |  5000     |
    When it recruits 5 more Sr. Dev and 150 more Jr. Dev employees
    Then the organization will have 205 Sr. Dev and 5150 Jr. Dev

Creating Test Runner Class

Create a cucumber test runner class as shown below:

package com.roytuts.cuke.flow;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
@RunWith(Cucumber.class)
@CucumberOptions(features = {
		"classpath:cuke/flow/feature/employeelist.feature" }, glue = "com.roytuts.cuke.flow.steps", monochrome = true, plugin = {
				"pretty", "html:target/cucumber", "json:target/Cucumber.json", "junit:target/Cucumber.xml" })
public class CukeEmployeeListRunner {
}

In the above class we have configured below features using @CucumberOptions:

  • features – location of the feature file
  • glue – the package where the step definition class will be written
  • monochrome – we want the output in console in human readable format
  • plugin – in what format and where we want the generated output file

Running the Runner Class

Once we run the above class the following steps are generated in the console:

Feature: An organization recruits few more employees
  """
  The organization got more projects from existing or new clients, so it has decided
  to recruit more employees to provide services to its customers
  """
  Scenario: An organization recruits employees based on designations # cuke/flow/feature/employeelist.feature:8
    Given an organization has employees
    When it recruits 5 more Sr. Dev and 150 more Jr. Dev employees
    Then the organization will have 205 Sr. Dev and 5150 Jr. Dev
1 Scenarios (1 undefined)
3 Steps (3 undefined)
0m0.000s
You can implement missing steps with the snippets below:
@Given("^an organization has employees$")
public void an_organization_has_employees(DataTable arg1) throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    // For automatic transformation, change DataTable to one of
    // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
    // E,K,V must be a scalar (String, Integer, Date, enum etc)
    throw new PendingException();
}
@When("^it recruits (\\d+) more Sr\\. Dev and (\\d+) more Jr\\. Dev employees$")
public void it_recruits_more_Sr_Dev_and_more_Jr_Dev_employees(int arg1, int arg2) throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}
@Then("^the organization will have (\\d+) Sr\\. Dev and (\\d+) Jr\\. Dev$")
public void the_organization_will_have_Sr_Dev_and_Jr_Dev(int arg1, int arg2) throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}

In the above class we see that the methods have been generated from the feature file and we also see that each of the method throws PendingException() because we have not yet implemented any step defined in feature file.

Creating Step Definition Class

Create a step definition class that will hold all generated steps with implementations. Modify the generated steps according to your needs.

package com.roytuts.cuke.flow.steps;
import java.util.HashMap;
import java.util.Map;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import cucumber.api.DataTable;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import gherkin.formatter.model.DataTableRow;
public class EmployeeListSteps {
	private int currTotalSrDev;
	private int currTotalJrDev;
	private Map<String, Integer> employeeMap;
	@Given("^an organization has employees$")
	public void an_organization_has_employees(DataTable employeeTable) throws Throwable {
		employeeMap = new HashMap<String, Integer>();
		for (DataTableRow row : employeeTable.getGherkinRows()) {
			employeeMap.put(row.getCells().get(0), Integer.parseInt(row.getCells().get(1)));
		}
	}
	@When("^it recruits (\\d+) more (.*) and (\\d+) more (.*) employees$")
	public void it_recruits_more_Sr_Dev_and_more_Jr_Dev_employees(int noOfSrDev, String srDev, int noOfJrDev,
			String jrDev) throws Throwable {
		currTotalSrDev = employeeMap.get(srDev) + noOfSrDev;
		currTotalJrDev = employeeMap.get(jrDev) + noOfJrDev;
	}
	@Then("^the organization will have (\\d+) Sr. Dev and (\\d+) Jr. Dev$")
	public void the_organization_will_have_Sr_Dev_and_Jr_Dev(int expTotalSrDev, int expTotalJrDev) throws Throwable {
		Assert.assertThat(currTotalSrDev, CoreMatchers.is(expTotalSrDev));
		Assert.assertThat(currTotalJrDev, CoreMatchers.is(expTotalJrDev));
	}
}

Now notice we have implemented all steps we have declared in feature file and now we should not get any exception while we execute the Runner class.

Note: The parameter DataTable in step @Given can be converted to any one of List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>, where E, K, V must be scalar, i.e., String, Integer, Date, enum, Double etc.

Running the Runner Class

Execute the cucumber test runner class we created earlier. You will see the below output in the console.

Feature: An organization recruits few more employees
  """
  The organization got more projects from existing or new clients, so it has decided
  to recruit more employees to provide services to its customers
  """
  Scenario: An organization recruits employees based on designations # cuke/flow/feature/employeelist.feature:8
    Given an organization has employees                              # EmployeeListSteps.an_organization_has_employees(DataTable)
    When it recruits 5 more Sr. Dev and 150 more Jr. Dev employees   # EmployeeListSteps.it_recruits_more_Sr_Dev_and_more_Jr_Dev_employees(int,String,int,String)
    Then the organization will have 205 Sr. Dev and 5150 Jr. Dev     # EmployeeListSteps.the_organization_will_have_Sr_Dev_and_Jr_Dev(int,int)
1 Scenarios (1 passed)
3 Steps (3 passed)
0m0.429s

Source Code

download source code

That’s all. Thanks for reading.

Leave a Comment