CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-cucumber--cucumber-java

Cucumber-JVM Java library providing annotation-based step definitions for Behavior-Driven Development (BDD) testing

Pending
Overview
Eval results
Files

data-handling.mddocs/

Data Handling

Robust data table and doc string handling with custom transformations and built-in collection support. Cucumber-Java provides comprehensive support for handling complex test data through data tables and doc strings with automatic conversion to Java collections and custom objects.

Capabilities

Data Tables

Access Gherkin data tables as various Java collection types with automatic type conversion and custom transformations.

/**
 * Raw DataTable access for maximum flexibility
 */
public void stepWithDataTable(DataTable table) {
    List<List<String>> rows = table.asLists();
    List<Map<String, String>> maps = table.asMaps();
}

/**
 * List of lists - each row as a list of strings
 */
public void stepWithListOfLists(List<List<String>> table) { }

/**
 * List of maps - each row as a map with headers as keys  
 */
public void stepWithListOfMaps(List<Map<String, String>> table) { }

/**
 * Single map - first column as keys, second column as values
 */
public void stepWithMap(Map<String, String> table) { }

/**
 * Map of lists - first column as keys, remaining columns as list values
 */
public void stepWithMapOfLists(Map<String, List<String>> table) { }

/**
 * Map of maps - first column as keys, headers and values as nested maps
 */
public void stepWithMapOfMaps(Map<String, Map<String, String>> table) { }

Usage Examples:

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

public class DataTableExamples {
    
    // Raw DataTable for custom processing
    @Given("the following data:")
    public void raw_data_table(DataTable table) {
        List<List<String>> rows = table.asLists();
        
        // Process headers
        List<String> headers = rows.get(0);
        
        // Process data rows
        for (int i = 1; i < rows.size(); i++) {
            List<String> row = rows.get(i);
            // Process each row
        }
        
        // Alternative: get as maps
        List<Map<String, String>> maps = table.asMaps(String.class, String.class);
        for (Map<String, String> rowMap : maps) {
            String name = rowMap.get("name");
            String email = rowMap.get("email");
        }
    }
    
    // List of lists - simple table structure
    @Given("the matrix:")
    public void matrix_data(List<List<String>> matrix) {
        for (List<String> row : matrix) {
            for (String cell : row) {
                // Process each cell
            }
        }
    }
    
    // List of maps - table with headers
    @Given("the following users exist:")
    public void users_exist(List<Map<String, String>> users) {
        for (Map<String, String> user : users) {
            String name = user.get("name");
            String email = user.get("email");
            int age = Integer.parseInt(user.get("age"));
            
            // Create user object
            createUser(name, email, age);
        }
    }
    
    // Single map - key-value pairs
    @Given("the configuration:")
    public void configuration(Map<String, String> config) {
        String environment = config.get("environment");
        String database = config.get("database");
        String timeout = config.get("timeout");
        
        // Apply configuration
        applyConfig(environment, database, timeout);
    }
    
    // Map of lists - grouped data
    @Given("the grouped data:")
    public void grouped_data(Map<String, List<String>> groups) {
        List<String> adminUsers = groups.get("admins");
        List<String> regularUsers = groups.get("users");
        List<String> guests = groups.get("guests");
        
        // Process each group
    }
    
    // Map of maps - hierarchical data
    @Given("the user profiles:")
    public void user_profiles(Map<String, Map<String, String>> profiles) {
        Map<String, String> johnProfile = profiles.get("john");
        String johnEmail = johnProfile.get("email");
        String johnRole = johnProfile.get("role");
        
        Map<String, String> janeProfile = profiles.get("jane");
        String janeEmail = janeProfile.get("email");
        String janeRole = janeProfile.get("role");
    }
}

Data Table Type Conversion

Automatic conversion of data tables to strongly-typed collections using built-in and custom type converters.

/**
 * Built-in numeric type conversions
 */
public void stepWithIntegers(List<List<Integer>> intTable) { }
public void stepWithDoubles(List<List<Double>> doubleTable) { }
public void stepWithFloats(List<List<Float>> floatTable) { }
public void stepWithLongs(List<List<Long>> longTable) { }
public void stepWithBigDecimals(List<List<BigDecimal>> decimalTable) { }
public void stepWithBigIntegers(List<List<BigInteger>> bigIntTable) { }

/**
 * Custom object conversion using @DataTableType
 */
public void stepWithCustomObjects(List<CustomObject> objects) { }

Usage Examples:

import java.math.BigDecimal;
import java.math.BigInteger;

public class TypedDataTableExamples {
    
    // Integer data table
    @Given("the following numbers:")
    public void numbers(List<List<Integer>> numberTable) {
        for (List<Integer> row : numberTable) {
            for (Integer number : row) {
                // Process integer values directly
                processNumber(number);
            }
        }
    }
    
    // Double precision data
    @Given("the coordinates:")
    public void coordinates(List<Map<String, Double>> coords) {
        for (Map<String, Double> coord : coords) {
            Double x = coord.get("x");
            Double y = coord.get("y");
            Double z = coord.get("z");
            
            // Work with double values directly
            plotPoint(x, y, z);
        }
    }
    
    // Financial data with BigDecimal
    @Given("the following prices:")
    public void prices(List<Map<String, BigDecimal>> priceData) {
        for (Map<String, BigDecimal> item : priceData) {
            String product = item.get("product").toString();
            BigDecimal price = item.get("price");
            BigDecimal tax = item.get("tax");
            
            // Precise decimal calculations
            BigDecimal total = price.add(tax);
        }
    }
    
    // Custom object conversion (requires @DataTableType)
    @Given("the following products:")
    public void products(List<Product> products) {
        for (Product product : products) {
            // Work with strongly-typed Product objects
            saveProduct(product);
        }
    }
    
    // Mixed type map
    @Given("the test data:")
    public void test_data(Map<String, Object> data) {
        // Note: requires @DefaultDataTableCellTransformer for Object conversion
        String name = (String) data.get("name");
        Integer count = (Integer) data.get("count");
        Boolean active = (Boolean) data.get("active");
    }
}

Doc Strings

Access Gherkin doc strings as raw strings or convert to custom objects using doc string type transformers.

/**
 * Raw doc string access
 */
public void stepWithDocString(String docString) { }

/**
 * DocString object with metadata
 */
public void stepWithDocStringObject(DocString docString) {
    String content = docString.getContent();
    String contentType = docString.getContentType();
}

/**
 * Custom object conversion using @DocStringType
 */
public void stepWithCustomDocString(CustomObject parsedDocString) { }

Usage Examples:

import io.cucumber.docstring.DocString;
import io.cucumber.java.en.Given;

public class DocStringExamples {
    
    // Raw string doc string
    @Given("the following JSON:")
    public void json_data(String jsonString) {
        // Parse JSON manually
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode json = mapper.readTree(jsonString);
            // Process JSON
        } catch (Exception e) {
            throw new RuntimeException("Invalid JSON", e);
        }
    }
    
    // DocString object with metadata
    @Given("the following document:")
    public void document_data(DocString docString) {
        String content = docString.getContent();
        String contentType = docString.getContentType(); // From """ content_type
        
        // Process based on content type
        if ("json".equals(contentType)) {
            processJsonContent(content);
        } else if ("xml".equals(contentType)) {
            processXmlContent(content);
        } else {
            processPlainText(content);
        }
    }
    
    // Multi-line text processing
    @Given("the following email template:")
    public void email_template(String template) {
        // Process multi-line email template
        String[] lines = template.split("\n");
        String subject = extractSubject(lines);
        String body = extractBody(lines);
        
        sendEmail(subject, body);
    }
    
    // Large text data
    @Given("the following log entries:")
    public void log_entries(String logData) {
        String[] entries = logData.split("\n");
        for (String entry : entries) {
            if (!entry.trim().isEmpty()) {
                parseLogEntry(entry);
            }
        }
    }
    
    // Custom parsed doc string (requires @DocStringType)
    @Given("the following configuration:")
    public void configuration(Properties config) {
        // Automatically parsed from doc string to Properties object
        String environment = config.getProperty("environment");
        String database = config.getProperty("database.url");
        
        applyConfiguration(config);
    }
    
    // Structured data from doc string
    @Given("the API response:")
    public void api_response(JsonNode response) {
        // Automatically parsed from JSON doc string
        String status = response.get("status").asText();
        JsonNode data = response.get("data");
        
        validateResponse(status, data);
    }
}

Advanced Data Table Features

Complex data table operations including transposition, custom transformations, and nested structures.

/**
 * Transposed data tables
 */
public void stepWithTransposedTable(@Transpose DataTable table) { }
public void stepWithTransposedObjects(@Transpose List<CustomObject> objects) { }

/**
 * Nested data structures
 */
public void stepWithNestedMaps(Map<String, Map<String, Object>> nestedData) { }
public void stepWithNestedLists(List<List<List<String>>> nestedLists) { }

/**
 * Custom replacement handling  
 */
public void stepWithReplacements(List<CustomObject> objects) { }
// Uses @DataTableType(replaceWithEmptyString = {"[blank]", "null"})

Usage Examples:

import io.cucumber.java.Transpose;
import io.cucumber.datatable.DataTable;

public class AdvancedDataTableExamples {
    
    // Transposed table for vertical data layout
    @Given("the user profile:")
    public void user_profile(@Transpose DataTable profile) {
        // Input table:     | name  | John Doe      |
        //                  | email | john@test.com |
        //                  | age   | 30            |
        //
        // After transpose: | name     | email         | age |
        //                  | John Doe | john@test.com | 30  |
        
        List<Map<String, String>> profileMaps = profile.asMaps();
        Map<String, String> userInfo = profileMaps.get(0);
        
        String name = userInfo.get("name");
        String email = userInfo.get("email");
        int age = Integer.parseInt(userInfo.get("age"));
    }
    
    // Complex nested structure
    @Given("the department structure:")
    public void department_structure(Map<String, Map<String, List<String>>> deptStructure) {
        // Table with department -> role -> list of people
        Map<String, List<String>> engineering = deptStructure.get("Engineering");
        List<String> developers = engineering.get("Developer");
        List<String> managers = engineering.get("Manager");
        
        assignPeopleToDepartment("Engineering", "Developer", developers);
        assignPeopleToDepartment("Engineering", "Manager", managers);
    }
    
    // Custom object with empty value handling
    @Given("the product catalog:")
    public void product_catalog(List<Product> products) {
        // Uses @DataTableType with replaceWithEmptyString configuration
        for (Product product : products) {
            // Empty/null values automatically handled by transformer
            if (product.getDescription() != null) {
                processDescription(product.getDescription());
            }
        }
    }
    
    // Multi-dimensional data
    @Given("the test matrix:")
    public void test_matrix(List<List<TestCase>> testMatrix) {
        for (int i = 0; i < testMatrix.size(); i++) {
            List<TestCase> row = testMatrix.get(i);
            for (int j = 0; j < row.size(); j++) {
                TestCase testCase = row.get(j);
                runTest(i, j, testCase);
            }
        }
    }
    
    // Dynamic column handling
    @Given("the dynamic data:")
    public void dynamic_data(DataTable table) {
        List<String> headers = table.row(0);
        
        for (int i = 1; i < table.height(); i++) {
            Map<String, String> rowData = new HashMap<>();
            List<String> row = table.row(i);
            
            for (int j = 0; j < headers.size(); j++) {
                String header = headers.get(j);
                String value = j < row.size() ? row.get(j) : "";
                rowData.put(header, value);
            }
            
            processDynamicRow(rowData);
        }
    }
}

Error Handling and Validation

Robust error handling and validation for data table and doc string processing.

public class DataValidationExamples {
    
    @Given("the validated user data:")
    public void validated_users(List<Map<String, String>> users) {
        for (Map<String, String> user : users) {
            // Validate required fields
            validateRequired(user, "name", "email");
            
            // Validate data formats
            String email = user.get("email");
            if (!isValidEmail(email)) {
                throw new IllegalArgumentException("Invalid email: " + email);
            }
            
            // Validate numeric fields
            String ageStr = user.get("age");
            if (ageStr != null && !ageStr.isEmpty()) {
                try {
                    int age = Integer.parseInt(ageStr);
                    if (age < 0 || age > 150) {
                        throw new IllegalArgumentException("Invalid age: " + age);
                    }
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException("Age must be a number: " + ageStr);
                }
            }
        }
    }
    
    @Given("the JSON configuration:")
    public void json_config(String jsonString) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode config = mapper.readTree(jsonString);
            
            // Validate required configuration fields
            if (!config.has("environment")) {
                throw new IllegalArgumentException("Missing required field: environment");
            }
            
            // Process validated configuration
            processConfiguration(config);
            
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("Invalid JSON configuration: " + e.getMessage());
        }
    }
    
    private void validateRequired(Map<String, String> data, String... fields) {
        for (String field : fields) {
            String value = data.get(field);
            if (value == null || value.trim().isEmpty()) {
                throw new IllegalArgumentException("Required field missing or empty: " + field);
            }
        }
    }
    
    private boolean isValidEmail(String email) {
        return email != null && email.contains("@") && email.contains(".");
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-cucumber--cucumber-java

docs

data-handling.md

hooks.md

index.md

parameter-transformation.md

runtime-context.md

step-definitions.md

tile.json