Cucumber Data Table – Convert a Two Column Table to a Map

Introduction

In this post you 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.

Related Posts:

Prerequisites

Java at least 1.8, Cucumber 1.2.5/6.10.3, Junit 4.12/5.8.0-M1, Maven 3.6.3

In this example I will show you how you 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 you can use in our step.

Project Setup

Create a maven based project in your favorite IDE or tool. The name of the project is java-cucumber-convert-two-columns-to-map. You can use below pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<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-convert-two-columns-to-map</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>12</maven.compiler.source>
		<maven.compiler.target>12</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>io.cucumber</groupId>
			<artifactId>cucumber-java</artifactId>
			<version>6.10.3</version>
		</dependency>

		<dependency>
			<groupId>io.cucumber</groupId>
			<artifactId>cucumber-junit</artifactId>
			<version>6.10.3</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<version>5.8.0-M1</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.junit.vintage</groupId>
			<artifactId>junit-vintage-engine</artifactId>
			<version>5.8.0-M1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
			</plugin>
		</plugins>
	</build>
</project>

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.

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

Test Runner Class

Create a cucumber test runner class as shown below:

package com.roytuts.cuke.flow;

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

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

@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 I have configured below features using @CucumberOptions:

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

Running the Runner Class

Once you 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 you see that the methods have been generated from the feature file and you also see that each of the method throws PendingException() because you have not yet implemented any step defined in feature file.

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;

//Cucumber 1.2.5
//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;
//Cucumber 1.2.5

import org.junit.jupiter.api.Assertions;

import io.cucumber.datatable.DataTable;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

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>();
		//Cucumber 1.2.5
		// for (DataTable row : employeeTable.getGherkinRows()) {
		// employeeMap.put(row.getCells().get(0),
		// Integer.parseInt(row.getCells().get(1)));
		// }
		//Cucumber 1.2.5
		employeeMap = employeeTable.asMap(String.class, Integer.class);
	}

	@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));//Junit 4
		// Assert.assertThat(currTotalJrDev, CoreMatchers.is(expTotalJrDev));//Junit 4

		Assertions.assertEquals(currTotalSrDev, expTotalSrDev); //Junit 5
		Assertions.assertEquals(currTotalJrDev, expTotalJrDev); //Junit 5
	}

}

Now notice I have implemented all steps I have declared in feature file and now you should not get any exception while you 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 I 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

Leave a Reply

Your email address will not be published. Required fields are marked *