or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-io-cucumber--cucumber-junit

JUnit 4 runner that enables executing Cucumber scenarios as JUnit tests, providing integration between Cucumber's behavior-driven development features and JUnit's testing framework

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/io.cucumber/cucumber-junit@7.22.x

To install, run

npx @tessl/cli install tessl/maven-io-cucumber--cucumber-junit@7.22.0

index.mddocs/

Cucumber JUnit

Cucumber JUnit is a JUnit 4 runner that enables executing Cucumber scenarios as JUnit tests, providing seamless integration between Cucumber's behavior-driven development (BDD) framework and JUnit's testing infrastructure. It allows developers to execute Cucumber scenarios written in Gherkin as standard JUnit tests, making BDD practices easily accessible within existing JUnit-based testing workflows.

Package Information

  • Package Name: cucumber-junit
  • Package Type: maven
  • Language: Java
  • Installation: Add to Maven pom.xml:
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-junit</artifactId>
        <version>7.22.1</version>
        <scope>test</scope>
    </dependency>

Core Imports

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

Basic Usage

package com.example;

import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.Cucumber;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(plugin = "pretty")
public class RunCucumberTest {
}

This creates a JUnit test runner that will execute all Cucumber scenarios in the same package as the runner class. By default, glue code (step definitions and hooks) is also assumed to be in the same package.

Architecture

Cucumber JUnit is built around several key components that integrate Cucumber's BDD framework with JUnit's testing infrastructure:

  • Cucumber Runner: The main Cucumber class extends JUnit's ParentRunner and orchestrates feature execution
  • Feature Processing: Parses Gherkin feature files and creates executable test scenarios using Cucumber Core
  • JUnit Integration: Maps Cucumber scenarios to JUnit test cases with proper descriptions and notifications
  • Configuration System: Layered options parsing from properties files, annotations, environment variables, and system properties
  • Plugin System: Extensible reporting and formatting through Cucumber's plugin architecture
  • Parallel Execution: Thread-safe execution supporting JUnit's RunnerScheduler for parallel test execution

The runner follows JUnit 4's ParentRunner pattern, creating child runners for each feature file and mapping scenarios to individual JUnit test cases.

Capabilities

JUnit Runner

The main JUnit 4 runner class for executing Cucumber scenarios as JUnit tests.

@API(status = API.Status.STABLE)
public final class Cucumber extends ParentRunner<ParentRunner<?>> {
    /**
     * Constructor called by JUnit to create the Cucumber runner.
     * Parses configuration options, initializes plugins, and creates feature runners.
     * 
     * @param clazz the test class annotated with @RunWith(Cucumber.class) 
     * @throws InitializationError if feature parsing fails, invalid options are provided,
     *         or the test class contains Cucumber annotations (step definitions/hooks)
     */
    public Cucumber(Class<?> clazz) throws InitializationError;
    
    /**
     * Set custom scheduler for parallel execution of feature files.
     * Enables thread-safe parallel execution across multiple threads.
     * 
     * @param scheduler the RunnerScheduler implementation to control parallel execution
     */
    public void setScheduler(RunnerScheduler scheduler);
}

Usage Example:

@RunWith(Cucumber.class)
@CucumberOptions(
    features = "src/test/resources/features",
    glue = "com.example.steps",
    tags = "@smoke and not @slow"
)
public class AcceptanceTest {
}

Configuration Options

Annotation for configuring Cucumber's execution options.

@API(status = API.Status.STABLE)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface CucumberOptions {
    /** Skip glue code execution */
    boolean dryRun() default false;
    
    /** Feature file paths */
    String[] features() default {};
    
    /** Package paths for step definitions and hooks */
    String[] glue() default {};
    
    /** Additional glue packages */
    String[] extraGlue() default {};
    
    /** Tag expression for filtering scenarios */
    String tags() default "";
    
    /** Register plugins (junit, html, pretty, progress, json, etc.) */
    String[] plugin() default {};
    
    /** Publish reports to https://reports.cucumber.io */
    boolean publish() default false;
    
    /** Disable colored terminal output */
    boolean monochrome() default false;
    
    /** Filter scenarios by name regex */
    String[] name() default {};
    
    /** Format of generated snippets */
    SnippetType snippets() default SnippetType.UNDERSCORE;
    
    /** Use filename compatible names */
    boolean useFileNameCompatibleName() default false;
    
    /** Include steps in notifications */
    boolean stepNotifications() default false;
    
    /** Custom ObjectFactory implementation */
    Class<? extends io.cucumber.core.backend.ObjectFactory> objectFactory() default NoObjectFactory.class;
    
    /** Custom UuidGenerator implementation */
    Class<? extends io.cucumber.core.eventbus.UuidGenerator> uuidGenerator() default NoUuidGenerator.class;
}

Usage Examples:

Basic configuration:

@CucumberOptions(
    plugin = "pretty",
    monochrome = true
)

Advanced configuration:

@CucumberOptions(
    features = {"src/test/resources/features/login", "src/test/resources/features/checkout"},
    glue = {"com.example.steps", "com.example.hooks"},
    tags = "@regression and not @slow",
    plugin = {
        "pretty", 
        "html:target/cucumber-reports",
        "json:target/cucumber-reports/Cucumber.json",
        "junit:target/cucumber-reports/Cucumber.xml"
    },
    stepNotifications = true,
    useFileNameCompatibleName = true
)

Feature path examples:

  • "src/test/resources/features" - All features in directory
  • "classpath:com/example/application" - All features in package
  • "src/test/resources/features/example.feature:42" - Specific scenario at line 42
  • "@target/rerun" - All scenarios in rerun files

Snippet Types

Enum for configuring the format of generated step definition snippets.

public enum SnippetType {
    /** Use underscore style for method names */
    UNDERSCORE,
    /** Use camel case style for method names */
    CAMELCASE
}

Usage Example:

@CucumberOptions(snippets = SnippetType.CAMELCASE)

Integration Features

JUnit Rules Support

Cucumber JUnit supports JUnit's @ClassRule, @BeforeClass, and @AfterClass annotations. These execute before and after all scenarios:

@RunWith(Cucumber.class)
public class RunCucumberTest {
    @ClassRule
    public static TestRule rule = new MyTestRule();
    
    @BeforeClass
    public static void setUp() {
        // Runs before all scenarios
    }
    
    @AfterClass
    public static void tearDown() {
        // Runs after all scenarios
    }
}

Note: Using JUnit rules limits portability between runners and may not execute correctly with command line, IntelliJ IDEA, or Cucumber-Eclipse. It's recommended to use Cucumber's @Before and @After hooks instead.

Assume Support

Cucumber JUnit supports JUnit's Assume functionality for conditional test execution:

import static org.junit.Assume.assumeTrue;

@Given("^a precondition is met$")
public void preconditionCheck() {
    assumeTrue("Skipping test due to environment", isEnvironmentReady());
}

Failed assumptions result in test abortion (marked as skipped) rather than failure.

Parallel Execution

Cucumber JUnit supports parallel execution of feature files across multiple threads. Configure with Maven Surefire plugin:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
        <parallel>both</parallel>
        <threadCount>4</threadCount>
    </configuration>
</plugin>

Error Handling

The runner validates configuration and throws InitializationError for:

  • Invalid feature paths
  • Parsing errors in feature files
  • Missing or invalid glue packages
  • Plugin configuration issues
  • Classes with Cucumber annotations (step definitions should be in separate classes)

Common exceptions during execution:

  • Step definitions are undefined (generates helpful snippets)
  • Scenarios are skipped due to failed assumptions
  • Feature parsing failures due to invalid Gherkin syntax

Undefined Step Exception

Exception thrown when step definitions are missing for scenario steps, providing helpful snippet suggestions.

/**
 * Exception thrown when Cucumber encounters undefined steps during execution.
 * Contains generated code snippets to help implement missing step definitions.
 */
final class UndefinedStepException extends RuntimeException {
    /**
     * Creates exception with snippet suggestions for undefined steps
     * @param suggestions Collection of step definition suggestions with generated code snippets
     */
    UndefinedStepException(Collection<Suggestion> suggestions);
}

This exception is thrown automatically by the Cucumber runner when scenarios contain steps that don't have corresponding step definitions. The exception message includes generated code snippets in the configured snippet format (underscore or camelcase).

Types

// JUnit framework types
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerScheduler;
import org.junit.runner.RunWith;

// Cucumber JUnit types
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.CucumberOptions.SnippetType;

// Cucumber core types (dependencies)
import io.cucumber.core.backend.ObjectFactory;
import io.cucumber.core.eventbus.UuidGenerator;
import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion;

// Annotation support
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apiguardian.api.API;

// Java standard library
import java.util.Collection;