Cucumber Configuration Overview in Cucumber JVM
1. Introduction to Cucumber Configuration
Cucumber Configuration is the set of settings that tells Cucumber JVM how to discover, filter, execute, and report BDD scenarios. A feature file describes behavior, and a step definition contains Java code, but Cucumber still needs instructions before it can connect those pieces together. It must know where feature files are stored, where glue code is located, which scenarios should run, which plugins should generate reports, and which execution options should be enabled for the current run.
In a real automation framework, configuration acts like the control center. It does not usually change what a scenario means, and it does not change what a step definition does internally. Instead, it controls how the framework is launched. The same feature files can be executed as smoke tests, regression tests, module-specific tests, dry-run validation, CI jobs, or local debugging runs depending on configuration.
Understanding configuration is essential for Cucumber JVM because many common failures are configuration failures. Undefined steps may happen because the glue package is wrong. No tests may run because the feature path is incorrect or tag filters exclude everything. Reports may be missing because plugins are not configured. Browsers may not open because dryRun is enabled. A strong Cucumber engineer can read configuration quickly and explain how it affects execution.
2. What Is Cucumber Configuration?
The Control Center of a Cucumber Project
Cucumber Configuration is the process of defining how Cucumber should run scenarios. It controls discovery, mapping, filtering, reporting, and optional execution behavior. It gives Cucumber operational instructions without requiring changes to the Gherkin scenarios or step definition implementation.
Configuration tells Cucumber where to find feature files:
features = "src/test/resources/features"
It tells Cucumber where to find step definitions and hooks:
glue = {"stepdefinitions", "hooks"}
It can also tell Cucumber which scenarios to execute, which report formats to create, whether to perform a dry run, whether to use cleaner console output, and how generated step definition snippets should be formatted. In short, configuration is the bridge between the project structure and the execution engine.
3. Why Configuration Is Important
Without proper configuration, Cucumber cannot reliably execute a framework. Feature files may exist, but Cucumber may not know where to find them. Step definitions may be implemented, but Cucumber may not scan their packages. Tags may be present, but execution may not filter them correctly. Reports may be expected, but no plugin may be configured to produce them.
Good configuration makes the framework flexible. The same codebase can run only smoke scenarios during a quick build, all regression scenarios overnight, only API-tagged scenarios in an integration pipeline, or dry-run validation before automation implementation. This flexibility matters when the number of scenarios grows.
Good configuration also makes the framework maintainable. Instead of hard-coding execution decisions inside step definitions or duplicating feature files, teams can use runner options, tags, plugins, profiles, and runtime properties. This keeps business scenarios clean and keeps execution concerns in the correct layer.
4. Where Cucumber Can Be Configured
Runner, Properties, Command Line, and CI
Cucumber JVM can be configured in several ways. The most common approach in many JUnit 4 projects is a runner class using @CucumberOptions. This is simple, visible, and easy for beginners to understand.
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/features",
glue = "stepdefinitions"
)
public class TestRunner {
}
JUnit 5 projects often use JUnit Platform configuration through junit-platform.properties or suite annotations. Maven and Gradle can pass runtime options through command-line properties. CI/CD systems can use environment variables or build parameters to choose tags, environments, report paths, and execution modes.
The important idea is that configuration may come from more than one place. A runner class may define defaults, while a Maven command overrides tags for a specific build. A CI pipeline may pass environment variables that change browser, environment, or tag selection. Teams should document which configuration source has authority so execution remains predictable.
5. Configuration Flow During Execution
When Cucumber starts, it reads configuration before it can execute scenarios. It uses configuration to locate features, locate glue, apply filters, load plugins, run or validate scenarios, and generate reports.
Runner or platform starts
|
v
Read Cucumber configuration
|
v
Locate feature files
|
v
Locate glue code
|
v
Apply tag filters
|
v
Load plugins
|
v
Execute or validate scenarios
|
v
Generate reports
This flow explains why configuration problems can stop execution very early. If the feature path is wrong, no scenarios are found. If glue is wrong, steps become undefined. If tag filters are wrong, expected scenarios may be skipped. If plugin paths are wrong, reports may not appear where the team expects them.
6. Main Cucumber Configuration Options
The most common @CucumberOptions settings are features, glue, plugin, tags, dryRun, monochrome, publish, and snippets. These settings cover most framework needs for discovery, execution control, and reporting.
| Option | Purpose |
|---|---|
| features | Defines feature file locations |
| glue | Defines step definition and hook packages |
| plugin | Defines reporting and output plugins |
| tags | Filters scenarios by tag expression |
| dryRun | Validates mappings without executing step code |
| monochrome | Improves console log readability |
| publish | Publishes reports to Cucumber report service when supported |
| snippets | Controls generated step definition method naming style |
These options should be used intentionally. A clean runner makes it obvious what the framework is going to run and what outputs it will produce.
7. Features Configuration
Locating Feature Files
The features option tells Cucumber where to search for .feature files. A common Maven project layout stores features under src/test/resources/features:
features = "src/test/resources/features"
Some projects use classpath-based configuration:
features = "classpath:features"
The chosen path should match the actual project structure. If the path is wrong, Cucumber may run zero scenarios or fail to find feature files. This can confuse teams because the feature files clearly exist in the repository, but Cucumber is looking somewhere else.
For large projects, features may be organized by domain modules such as login, checkout, payment, account, search, or reporting. The configuration can point to the root features folder and tags can control execution, or separate runners can point to module-specific folders when there is a clear reason.
8. Glue Configuration
The glue option tells Cucumber where step definitions and hooks are located. Glue is critical because it controls step discovery. If the glue package is wrong, Cucumber cannot map Gherkin steps even when Java methods exist in the project.
glue = {
"stepdefinitions",
"hooks"
}
In larger projects, package names are often fully qualified:
glue = {
"com.softwaretips4u.steps",
"com.softwaretips4u.hooks"
}
Glue should include step definition packages and hook packages, not page object packages, utility packages, or model packages unless those packages intentionally contain Cucumber annotations. Keeping glue clean helps prevent accidental discovery of duplicate or misplaced step definitions.
9. Plugin Configuration
Reports and Execution Output
Plugins control how Cucumber outputs execution information and reports. They can produce readable console logs, HTML reports, JSON reports, JUnit XML reports, timeline output, message reports, and integrations with external reporting tools.
plugin = {
"pretty",
"html:target/cucumber-report.html",
"json:target/cucumber.json",
"junit:target/cucumber.xml"
}
The pretty plugin improves console readability. HTML reports are useful for humans. JSON reports are often consumed by reporting tools. JUnit XML reports are useful in CI/CD systems because many CI servers understand JUnit-style test results.
Plugin configuration should be chosen based on how results are consumed. A local developer may mainly need console output and an HTML report. A CI pipeline may need JSON and JUnit XML for dashboards and trend reporting. Teams should avoid report paths that overwrite unrelated outputs unless that behavior is intentional.
10. Tag Configuration
Tags allow teams to select which scenarios should run. They are one of the most important configuration tools in a scalable Cucumber framework. A tag expression can run smoke tests, regression tests, module-specific tests, work-in-progress scenarios, or environment-specific scenarios.
tags = "@smoke"
More complex expressions are also possible:
tags = "@smoke and not @wip"
Tags are case-sensitive. @Smoke and @smoke are different tags. A wrong tag expression can accidentally skip all scenarios or include scenarios that should not run in a particular pipeline.
Good tag strategy avoids duplicating feature files. Instead of creating separate feature copies for smoke and regression, tag the right scenarios and use configuration to choose them. This keeps behavior documentation centralized and avoids drift between duplicate files.
11. Dry Run Configuration
Mapping Validation Mode
The dryRun option validates feature files and step mappings without executing automation code. It is useful while developing new scenarios or refactoring glue packages.
dryRun = true
When dry run is enabled, Cucumber parses features, searches glue packages, checks whether steps are mapped, and reports undefined or ambiguous steps. It does not open browsers, call APIs, access databases, or run assertions.
Before running actual automation, dryRun must be disabled:
dryRun = false
A common mistake is leaving dryRun = true in a regression runner and wondering why nothing executes. For that reason, many teams keep dry-run validation in a separate runner or build profile.
12. Monochrome Configuration
The monochrome option improves console output readability by removing unnecessary ANSI color codes and formatting artifacts from logs. It is especially useful in CI tools such as Jenkins, where raw color codes can make logs harder to read.
monochrome = true
Monochrome does not affect scenario behavior. It only affects output formatting. In local IDE runs, colored output may be acceptable. In CI logs, clean monochrome output is often easier to scan and archive.
Because this option has low risk and improves readability, many teams keep monochrome enabled by default in runner configuration.
13. Publish Configuration
The publish option controls whether Cucumber publishes execution results to the Cucumber Reports service when supported by the project and version. When enabled, Cucumber may generate a shareable report URL after execution.
publish = true
This can be useful for collaboration when team members need to review reports online. However, teams should understand organizational policies before publishing execution data externally. Some projects may prefer local reports only due to privacy, security, or compliance requirements.
The best practice is to decide intentionally whether publish should be enabled. Do not enable it blindly in every project. If it is used, document when and where report links are expected.
14. Snippet Configuration
Generated Step Definition Style
The snippets option controls how generated step definition method names look when Cucumber suggests missing step definitions. This matters when Cucumber reports undefined steps and prints templates in the console.
snippets = SnippetType.CAMELCASE
With camel case, Cucumber may generate:
public void userLogsIn() {
}
With underscore style, it may generate:
public void user_logs_in() {
}
The annotation text controls mapping, not the generated method name. Still, snippet style affects code readability and team convention. Java teams often prefer camelCase because it matches normal Java method naming style.
15. Complete Configuration Example
A complete JUnit 4 runner may combine several configuration options:
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/features",
glue = {
"stepdefinitions",
"hooks"
},
plugin = {
"pretty",
"html:target/report.html",
"json:target/report.json",
"junit:target/report.xml"
},
tags = "@smoke",
dryRun = false,
monochrome = true,
publish = false,
snippets = SnippetType.CAMELCASE
)
public class TestRunner {
}
This configuration says where features live, where glue code lives, which reports to generate, which scenarios to run, whether to execute step bodies, how console output should look, whether to publish reports, and how generated snippets should be named. A developer reading this runner can understand the execution behavior without opening feature files or step definitions.
16. Configuration Hierarchy
Configuration can be understood as layers. The project contains feature files, step definitions, hooks, reports, and build configuration. The runner or platform configuration selects which parts of that project Cucumber should use for a given run.
Project
|
v
Runner or JUnit Platform
|
v
Cucumber configuration
|
v
Features, glue, tags, plugins, reports, execution options
In some projects, command-line options or CI variables override runner defaults. This is powerful, but it should be controlled. If developers do not know where a setting comes from, debugging becomes harder. Keep configuration centralized where possible and document any runtime overrides used by build pipelines.
17. Maven and Command-Line Configuration
Runtime Overrides
Maven commands can pass Cucumber options at runtime. For example, a team may run only smoke scenarios with a command-line tag filter:
mvn test -Dcucumber.filter.tags="@smoke"
This is useful in CI/CD because the same test code can support different execution types. A pull request build can run smoke tests, a nightly job can run regression tests, and a release pipeline can run critical tagged scenarios.
Runtime overrides should not become chaotic. If every developer uses different undocumented command options, results become difficult to compare. Use documented scripts, Maven profiles, or CI job names so everyone understands which configuration is being applied.
18. JUnit Platform Configuration
Modern Cucumber JVM projects using JUnit 5 may configure Cucumber through the JUnit Platform. A common file is junit-platform.properties under test resources. This approach keeps configuration separate from Java runner code and works well with platform-based test discovery.
cucumber.features=classpath:features
cucumber.glue=stepdefinitions,hooks
cucumber.plugin=pretty,html:target/cucumber-report.html
cucumber.filter.tags=@smoke
The exact property names depend on the Cucumber and JUnit Platform version used by the project. The concept is the same: define feature locations, glue, plugins, tags, and other options outside the feature files themselves.
JUnit Platform configuration is helpful for teams standardizing on newer test infrastructure. It can reduce runner-class clutter and align Cucumber execution with other JUnit 5 tests.
19. Environment Variables in CI/CD
Environment variables are commonly used in CI/CD pipelines to control runtime choices such as environment, browser, tag selection, report location, or whether publishing is enabled. For example, a CI job may pass a tag expression for a particular pipeline stage.
This is useful because CI jobs often need different behavior from local development. A local run may use @smoke and a local browser. A nightly CI run may use @regression and a remote grid. A release job may use @critical and publish reports.
However, environment-based configuration must be transparent. Pipeline logs should show the selected tags, environment, browser, and report paths. Hidden configuration makes failures harder to reproduce locally.
20. Common Mistake: Wrong Feature Path
A wrong feature path prevents Cucumber from finding scenarios. For example:
features = "feature"
If the actual folder is src/test/resources/features, Cucumber may run nothing or report that it cannot find feature files. The correct setting should match the project structure:
features = "src/test/resources/features"
This mistake often happens when a project is copied from a tutorial but the folder names are changed. Always verify feature paths after creating or restructuring a project.
21. Common Mistake: Incorrect Glue Package
Incorrect glue configuration causes undefined steps even when step definition methods exist. For example, the runner may say:
glue = "steps"
But the actual package may be:
package stepdefinitions;
Cucumber searches steps but the methods are in stepdefinitions. The result is undefined steps. The fix is to align glue configuration with the actual Java package names.
This is one of the first things to check when many steps suddenly become undefined after refactoring.
22. Common Mistake: Missing Plugin Configuration
If plugin configuration is missing, scenarios may execute but expected reports may not be generated. This can be a problem in CI because teams rely on HTML, JSON, or JUnit XML reports to analyze results.
plugin = {
"pretty",
"html:target/cucumber-report.html",
"json:target/cucumber.json"
}
Report paths should be stable and included in CI artifact publishing rules. If the plugin writes reports to target but the CI job archives a different folder, reports may appear missing even though they were generated.
23. Common Mistake: Wrong Tag Expression
Tag expressions are powerful but easy to mistype. Tags are case-sensitive, so @Smoke does not match @smoke. A wrong expression can skip scenarios silently if the team does not check execution counts.
tags = "@Smoke"
If the feature files use @smoke, this configuration will not select those scenarios. Complex expressions also need care:
tags = "@smoke and not @wip"
Use consistent tag naming and review execution summaries. If zero scenarios run unexpectedly, tag filters should be one of the first things to inspect.
24. Best Practices for Cucumber Configuration
Keep Configuration Simple and Intentional
Keep configuration centralized where possible. A runner, platform properties file, or build profile should clearly describe how Cucumber is launched. Avoid scattering important execution decisions across unrelated files unless there is a documented reason.
Use the standard Maven structure unless the project has a strong reason to do otherwise. Keep feature files under src/test/resources/features and Java step definitions under src/test/java packages. Organize glue packages by business module, and keep hooks in a clear hook package.
Configure multiple report formats when the results are consumed by different tools. Use HTML for human review, JSON for reporting integrations, and JUnit XML for CI test result publishing. Use tags for execution selection rather than duplicating feature files. Keep dry run separate from regression execution.
- Use clear feature and glue paths.
- Keep runner configuration readable and version-controlled.
- Use tags to select scenarios for smoke, regression, and modules.
- Enable useful reports for local and CI execution.
- Use dryRun only for mapping validation.
- Document command-line and CI overrides.
25. Configuration in Scalable Frameworks
As a framework grows, configuration becomes more important. A small project may have one runner and one feature folder. A larger project may have multiple modules, tag groups, report formats, browser choices, environments, and CI pipelines. Configuration should support that growth without making execution confusing.
A scalable framework separates business behavior from execution decisions. Feature files should not be duplicated for different environments. Step definitions should not contain hard-coded pipeline logic. Runner and build configuration should decide which scenarios run and how reports are generated.
For example, a smoke pipeline may run @smoke and generate quick reports. A nightly pipeline may run @regression and publish detailed artifacts. A local developer may run one feature file for debugging. All of these runs can use the same feature and step code with different configuration.
26. Troubleshooting Configuration Problems
A Practical Debugging Checklist
When Cucumber does not behave as expected, start with configuration. If no scenarios run, check the feature path and tag filters. If steps are undefined, check glue packages and annotation text. If reports are missing, check plugin configuration and output paths. If dry run completes but no browser opens, check whether dryRun is still true.
When CI behaves differently from local execution, compare the exact commands. Look at Maven profiles, Gradle tasks, system properties, environment variables, runner classes, tag expressions, and report artifact settings. Many "CI-only" Cucumber problems come from different configuration rather than different application behavior.
Good troubleshooting means reading the runner and build command before changing feature files or step definitions. Configuration is often the shortest path to the real cause.
27. Multiple Runner Strategy
When Separate Runners Make Sense
Some Cucumber JVM frameworks use more than one runner class. For example, a project may have SmokeRunner, RegressionRunner, DryRunRunner, and ModuleRunner classes. Each runner can point to the same feature root but use different tags, plugins, or dry run settings. This approach can be easy for beginners because the execution intention is visible in the class name.
@CucumberOptions(
features = "src/test/resources/features",
glue = {"stepdefinitions", "hooks"},
tags = "@smoke",
plugin = {"pretty", "html:target/smoke-report.html"},
monochrome = true
)
public class SmokeRunner {
}
Multiple runners are useful when the project has a small number of stable execution modes. They become problematic when every minor variation gets its own runner. Too many runners create duplicated configuration and make maintenance harder. If ten runner classes repeat the same feature path, glue path, and plugin list, a future package change must be updated in ten places.
A practical balance is to keep a few clear runners for common workflows and use build profiles or command-line overrides for variable details. For example, a SmokeRunner may be stable, while the browser or environment can be selected by system properties. This keeps configuration understandable without creating unnecessary duplication.
28. Maven Profiles and Build-Level Configuration
Maven profiles are commonly used to define different execution modes. A smoke profile may pass @smoke tags, a regression profile may pass @regression, and a dry-run profile may enable mapping validation. This lets teams run predictable commands instead of remembering long property lists.
mvn test -Psmoke
mvn test -Pregression
mvn test -Pdry-run
Build-level configuration is helpful in CI/CD because the pipeline can call a named profile. The profile documents the purpose of the run and reduces command-line mistakes. It also allows report paths, tag filters, and execution options to be standardized across team members and agents.
The risk is hidden behavior. If a profile changes tags, report paths, or runtime options, developers must be able to find that configuration quickly. Keep profile names meaningful, avoid surprising overrides, and document the most common commands in the project README or test framework guide.
29. Configuration Ownership and Maintenance
Keep Execution Rules Under Control
Configuration should have clear ownership. In many teams, the automation framework owner or SDET lead is responsible for runner classes, tag strategy, report plugins, and CI execution settings. This does not mean others cannot change configuration, but it does mean changes should be reviewed carefully because configuration affects the entire test suite.
A small configuration change can have a large impact. Changing glue can make hundreds of steps undefined. Changing tags can skip critical scenarios. Changing report paths can break CI publishing. Enabling dryRun can make a suite appear to complete without executing automation. Because of this, configuration changes deserve the same review quality as code changes.
Good maintenance includes removing obsolete runners, deleting unused tags, keeping report paths consistent, and ensuring CI commands match documented local commands. When the framework grows, configuration should be periodically reviewed to make sure it still reflects how the team actually runs tests.
Configuration should also be easy to explain to a new team member. If someone joins the project and cannot tell which command runs smoke tests, which command validates mappings, where reports are generated, or which glue packages are active, the configuration has become too hidden. Clear configuration reduces onboarding time and prevents accidental misuse of the framework.
30. Interview-Ready Summary
Short Explanation for Interviews
Cucumber Configuration controls how Cucumber discovers, executes, filters, and reports scenarios. In Cucumber JVM, common configuration mechanisms include @CucumberOptions, JUnit Platform properties, Maven or Gradle command-line options, system properties, and CI environment variables. Important options include features, glue, plugin, tags, dryRun, monochrome, publish, and snippets.
A strong interview answer should explain that features tells Cucumber where feature files are located, glue tells it where step definitions and hooks are located, plugin controls reporting, tags filter scenario execution, dryRun validates mappings without executing automation, monochrome cleans console output, publish can share reports, and snippets controls generated step method style.
- Configuration is the control center of a Cucumber JVM project.
- Wrong feature paths can prevent scenarios from running.
- Wrong glue paths commonly cause undefined steps.
- Plugins generate useful reports for local and CI execution.
- Tags make execution flexible without duplicating feature files.
- Good configuration makes frameworks scalable and CI/CD friendly.
31. Golden Rule
The golden rule is simple: Cucumber configuration should clearly tell the framework what to run, where to find it, how to filter it, and how to report it. Feature files should describe business behavior. Step definitions should implement automation. Configuration should control execution.
When configuration is clean, a Cucumber JVM framework is easier to run locally, easier to debug, easier to scale, and easier to integrate with CI/CD. When configuration is scattered or unclear, teams waste time on missing features, undefined steps, empty runs, broken reports, and inconsistent pipeline behavior. Strong configuration discipline is one of the foundations of a reliable BDD automation framework.