Feature Path Configuration in Cucumber JVM
What Is Feature Path Configuration?
Feature Path Configuration is the process of telling Cucumber where to find the .feature files that contain BDD scenarios. Feature files are not Java classes, so Cucumber must be given a location before it can discover and execute them. The feature path may point to one file, one folder, multiple folders, or a classpath resource depending on whether the project uses JUnit 4, TestNG, or JUnit Platform.
In simple terms, feature path configuration tells Cucumber where the feature files are stored. Without this configuration, Cucumber may start but find no scenarios. With the correct configuration, it can locate the Gherkin files, parse scenarios, match steps to glue code, execute hooks, run automation code, and generate reports.
Why Feature Path Configuration Matters
A Cucumber framework usually contains Java source code, test resources, configuration files, reports, build output, and dependency files. Feature files are part of test resources because they describe test behavior rather than Java implementation. In Maven and Gradle projects, the recommended location is normally src/test/resources/features.
Correct feature paths improve reliability and maintainability. When the feature path points to a clear root folder, Cucumber can discover all relevant scenarios recursively. When feature paths are scattered or hardcoded inconsistently across runners, teams spend time debugging missing scenarios, skipped modules, and confusing CI results.
Recommended Project Location
The most common structure places feature files under the test resources directory. This follows Java build conventions and keeps Gherkin files separate from Java classes.
src
test
java
runners
stepdefinitions
hooks
resources
features
login.feature
payment.feature
customer.feature
This structure is clean because Java code stays in src/test/java and non-Java resources stay in src/test/resources. During test execution, resources are placed on the test classpath, which is especially useful for JUnit Platform configuration.
Configuration with JUnit 4 or TestNG
In JUnit 4 and TestNG runner classes, feature paths are commonly configured through the features attribute of @CucumberOptions.
@CucumberOptions(
features = "src/test/resources/features",
glue = "stepdefinitions"
)
public class TestRunner {
}
This tells Cucumber to search the features folder for feature files. If the folder contains subfolders, Cucumber can discover files recursively. The glue setting is separate. Feature path tells Cucumber where the Gherkin files are. Glue tells Cucumber where the Java step definitions and hooks are.
Configuration with JUnit Platform
In JUnit 5 style projects, Cucumber commonly integrates through the JUnit Platform engine. Instead of pointing to a physical source folder path, the suite often selects a classpath resource.
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
public class RunCucumberTest {
}
Here, features refers to the resource folder available on the test classpath. If the project stores files under src/test/resources/features, selecting features is usually correct. This distinction is important: JUnit 4 examples often use source folder paths, while JUnit Platform examples often use classpath resource names.
Single Feature File
Sometimes a developer or tester wants to execute only one feature file while building or debugging a scenario. The runner can point directly to that file.
@CucumberOptions(
features = "src/test/resources/features/login.feature"
)
This executes all scenarios in login.feature. It is useful during local debugging, but it should not become the normal long-term execution strategy for a large suite. Permanent runners should usually point to stable folders and use tags for scenario selection.
Multiple Feature Files and Folders
Cucumber can also use multiple feature locations. This is useful when a runner must execute selected modules such as login and payment.
@CucumberOptions(
features = {
"src/test/resources/features/login.feature",
"src/test/resources/features/payment.feature"
}
)
For folders, the same pattern works:
@CucumberOptions(
features = {
"src/test/resources/features/login",
"src/test/resources/features/payment"
}
)
This configuration is clear when the execution boundary is genuinely folder-based. However, if the goal is to run smoke scenarios across many modules, tags are usually a better choice than multiple folder paths.
Using the Root Features Folder
Large projects often organize feature files into business-oriented subfolders. A root feature path can still execute everything.
features
authentication
login.feature
logout.feature
customer
create-customer.feature
update-customer.feature
payment
card-payment.feature
refund.feature
order
place-order.feature
cancel-order.feature
@CucumberOptions(
features = "src/test/resources/features"
)
With this setup, Cucumber discovers the files under the root folder recursively. This is practical because the runner stays stable even when new module folders are added. When a new feature file is placed under the features tree, it becomes available for execution automatically.
Feature Path vs Glue
Feature path and glue are related but different. Feature path points to Gherkin files. Glue points to Java support code. Both must be configured correctly for execution to work.
| Configuration | Purpose | Example |
|---|---|---|
| Feature path | Finds .feature files | src/test/resources/features |
| Glue | Finds step definitions and hooks | stepdefinitions |
A correct feature path with wrong glue still leads to undefined steps. Correct glue with wrong feature path leads to no scenario discovery. Good framework setup validates both.
Feature Path vs Tags
Feature paths select files or folders. Tags select scenarios. This distinction matters in real execution. If you point to the payment folder, you run payment feature files. If you use @Smoke, you run smoke scenarios wherever they exist in the selected feature path.
@CucumberOptions(
features = "src/test/resources/features",
tags = "@Smoke"
)
This runner searches all feature files under the root folder but executes only smoke scenarios. This is usually better than moving files around or changing feature paths whenever the team wants a different suite.
Enterprise Folder Strategy
Enterprise frameworks should organize feature files by business capability rather than by technical implementation. Folder names such as authentication, customer, order, payment, reports, and search are easier for business and QA teams to understand than folders named screens, pages, buttons, or selenium-tests.
src/test/resources/features
authentication
customer
order
payment
reporting
api
This structure supports growth. A new customer feature can go into the customer folder. A new payment behavior can go into the payment folder. The root runner can still discover everything, while tags can select smoke, regression, API, UI, or critical scenarios.
Common Mistakes
Wrong Folder Name
Using features = "feature" when the actual folder is features prevents discovery. Small spelling differences can stop the whole suite from running.
Wrong Relative Path
Using resources/features instead of src/test/resources/features is common in JUnit 4 and TestNG examples. Make sure the path style matches the runner type and project structure.
Putting Feature Files Under Java Source
Feature files should not be stored under src/test/java. Java source folders should contain Java code. Feature files belong under test resources.
Wrong File Extension
Cucumber recognizes .feature files. Files named login.txt or login.gherkin will not be treated as feature files in the normal setup.
Changing Paths Instead of Using Tags
Constantly editing feature paths for selective execution creates confusion. Use tags for most suite selection needs, especially smoke, regression, module, priority, and technology filters.
Best Practices
Store all feature files under src/test/resources/features. Organize large projects into business-oriented subfolders. Point stable runners to the root features folder whenever practical. Use tags to select scenarios instead of changing feature paths frequently. Keep feature files separate from Java code. Use meaningful folder names that reflect the domain.
For JUnit Platform projects, prefer classpath resource selection such as @SelectClasspathResource("features"). For JUnit 4 and TestNG projects, use the features attribute in @CucumberOptions. Be clear about the difference between physical source paths and classpath resources.
Debugging Feature Path Issues
If Cucumber does not run expected scenarios, first verify the folder exists. Then verify the file extension. Then confirm whether the runner points to a folder, a subfolder, or one specific file. If using JUnit Platform, confirm that the resource is under src/test/resources and available on the test classpath.
If scenarios exist but are not executed, inspect tag filters. The feature path may be correct, but the tag expression may exclude the scenarios. If the scenarios execute but steps are undefined, the issue is not the feature path; it is likely glue configuration.
Classpath Resource vs File System Path
Beginners often confuse file system paths and classpath resources. In a JUnit 4 or TestNG runner, examples often use a file system style path such as src/test/resources/features. In JUnit Platform examples, @SelectClasspathResource("features") means Cucumber should look for a resource named features on the test classpath. These two styles point to the same logical folder in many Maven projects, but they are not written the same way.
This distinction matters in CI and packaged execution. The test resources folder is copied to the test output directory by the build tool. A classpath resource selector does not need the full source folder prefix. If a team copies a JUnit 4 path directly into a JUnit Platform suite, discovery may fail. If a team uses a classpath-style value in an older runner that expects a file path, discovery may also fail.
When changing runner style, review feature path configuration carefully. Migration from JUnit 4 to JUnit Platform is not only a dependency change; it also changes how resources are selected. A simple smoke feature is useful for confirming that discovery works after migration.
Adding New Pages or Modules to the Feature Folder
A good feature path strategy should make growth easy. When a new business module is added, the team should be able to create a new folder under features and add feature files without changing every runner. Pointing stable runners to the root features folder supports this. Tags can then decide whether the new scenarios participate in smoke, regression, API, UI, or release suites.
For example, if a project adds a rewards module, the team can create src/test/resources/features/rewards. If the root runner points to src/test/resources/features, the new module is discoverable immediately. The team can then tag important scenarios with @Smoke or @Regression based on execution needs.
This approach is better than creating a special runner for every folder. Module-specific runners can still exist when there is a strong reason, but the default should be a simple, scalable root discovery model. This keeps the execution structure predictable as the suite grows.
Feature Path Strategy for Large Teams
Large teams need naming conventions. Folder names should be stable, readable, and business-oriented. Avoid names based on temporary sprint numbers, individual testers, or UI page names. Folder names should describe capabilities that make sense over time: authentication, customer, order, payment, search, reporting, notification, and account management.
Feature file names should also be descriptive. A file named login.feature is clearer than test1.feature. A file named payment-refund.feature is clearer than refundcases.feature. Good names help reviewers, product owners, testers, and developers understand the suite without opening every file.
Ownership can be documented separately through tags, README files, or team conventions. Do not encode every responsibility into folder paths. If paths become too deep, execution and navigation become harder. A practical structure is usually two or three levels deep, not seven levels deep.
Feature Path Configuration in CI/CD
In CI/CD, feature path configuration must behave the same way on build agents as it does locally. Paths that depend on a developer's machine, absolute directories, or IDE working directories are fragile. Use project-relative paths or classpath resources. This ensures that Jenkins, GitHub Actions, Azure DevOps, and local machines all discover the same feature files.
CI jobs should also confirm scenario counts. If a pipeline is expected to run 200 regression scenarios but reports zero scenarios, the problem may be feature discovery, tag filtering, or a build configuration issue. A reliable pipeline makes empty execution visible. Teams should treat unexpected zero-scenario runs as failures, not successes.
When a new feature folder is added, CI should pick it up automatically if the runner points to the root features folder. This is one reason root-folder discovery plus tags is a strong pattern. The feature path remains stable while the suite evolves.
Interview-Ready Summary
Feature Path Configuration tells Cucumber where to locate .feature files. In JUnit 4 and TestNG projects, it is usually configured through the features attribute of @CucumberOptions. In JUnit 5 projects, it is commonly configured using @SelectClasspathResource with the Cucumber JUnit Platform engine.
The recommended location is src/test/resources/features. Feature files can be organized into module-based subfolders, and Cucumber can discover them recursively when the runner points to the root features folder. Feature paths select files, while tags select scenarios. Good frameworks use both correctly.
The golden rule is simple: store feature files under test resources, configure the runner to the correct location, organize features by business module, and use tags for selective scenario execution instead of constantly changing paths.