Using Cucumber Data Tables to Parameterize Tabular Test Data
Learn how Cucumber Data Tables let you pass tabular test data to a single step definition, improving readability and type safety.
17 May 2026, 08:49 UTC

Problem: Repeating Similar Steps for Tabular Data
When a scenario needs to validate a list of users, products, or configuration rows, writing a separate Given/When/Then for each row clutters the feature file and obscures the business intent.
Thesis: Cucumber Data Tables let you pass a collection of rows to a single step definition, keeping the scenario readable while providing type‑safe access to each record.
How Data Tables Work
In Gherkin a step can end with a table delimited by | symbols. Cucumber passes that table to the step definition as an io.cucumber.datatable.DataTable object. By annotating the parameter with @io.cucumber.datatable.DataTableType you can teach Cucumber how to convert each raw cell into a domain object (POJO, record, or map). The step then receives a List<YourType> (or Map<String,YourType>) that you can iterate over.
Worked Example: Validating a List of Users
1. Feature file
Feature: User administration
Scenario: Bulk create users
Given the system contains the following users:
| firstName | lastName | email |
| Alice | Smith | alice@example.com |
| Bob | Jones | bob@example.com |
| Carol | Lee | carol@example.com |
When the import job runs
Then all users should be active
2. Step definition with DataTableType
import io.cucumber.datatable.DataTableType;
import io.cucumber.java.en.Given;
import java.util.List;
import java.util.Map;
public class UserSteps {
// POJO that matches the column names
public static class User {
private String firstName;
private String lastName;
private String email;
// getters and setters omitted for brevity
}
@DataTableType
public User userEntry(Map row) {
User u = new User();
u.setFirstName(row.get("firstName"));
u.setLastName(row.get("lastName"));
u.setEmail(row.get("email"));
return u;
}
@Given("the system contains the following users:")
public void the_system_contains_the_following_users(List users) {
// users now holds three User objects, one per table row
for (User u : users) {
// Example: delegate to a service or repository
UserService.create(u.getFirstName(), u.getLastName(), u.getEmail());
}
}
// … other steps …
}
3. Running the test
Execute the feature with JUnit 5 (or Maven): mvn test
Check the console output; you should see the step invoked once and the list size logged as 3. No step is duplicated for each row.
Trade‑off and Limitations
- Readability: Very wide tables (many columns) or many rows can make the feature file hard to scan; consider extracting reusable tables or using Scenario Outline with Examples when the data drives distinct business rules.
- Performance: Each row is still processed as part of a single step invocation, so large tables do not multiply step overhead, but the conversion logic runs for every cell; extremely large datasets (thousands of rows) may increase execution time and memory use.
- Complex nesting: If your data includes nested objects or lists, you need a custom DataTableType that builds the hierarchy, which adds boilerplate and requires careful maintenance.
Comparison: Data Table vs Scenario Outline
| Aspect | Data Table | Scenario Outline |
|---|---|---|
| When to use | Same action performed on a set of related rows | Different outcomes or variations per row |
| Step invocation count | One step per Gherkin line (table passed as argument) | One step per row (scenario executed repeatedly) |
| Readability | Compact for homogeneous data | Clear when each row needs distinct assertions |
| Setup effort | Requires DataTableType for type safety | Uses <placeholder> syntax in steps |
Actionable Closing
Start small: replace a repetitive Given/When/Then block that handles a simple two‑column list with a Data Table and a DataTableType converter. Verify that the step receives a List of the expected POJO and that your assertions work on the mapped fields. As the table grows, monitor readability and execution time; if the table becomes a wall of text, split it into logical chunks or revert to a Scenario Outline for varied outcomes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.