What is a Test Runner in Cucumber?
A Test Runner is a Java class in a Cucumber project that serves as the entry point for running tests. It uses the @RunWith(Cucumber.class) annotation to integrate with JUnit and the @CucumberOptions annotation to configure test execution, specifying details like feature file locations, step definition packages, tags, and plugins. The Test Runner acts as a coordinator, ensuring that Cucumber executes your scenarios correctly and generates the desired reports.
Why Use a Test Runner?
- Centralized Configuration: Define all test execution settings in one place.
- Test Execution: Run feature files and step definitions seamlessly with JUnit.
- Customization: Filter tests by tags, select report formats, and enable/disable features.
- CI/CD Integration: Integrate with build tools like Maven and CI systems like Jenkins.
- Scalability: Manage large test suites with clear organization.
How a Test Runner Works
The Test Runner class is annotated with:
@RunWith(Cucumber.class): Tells JUnit to use Cucumber’s test runner instead of the default JUnit runner.@CucumberOptions: Configures options like:features: Path to feature files.glue: Package(s) containing step definitions and hooks.tags: Filters scenarios by tags.plugin: Specifies report formats.monochrome: Improves console output readability.dryRun: Checks for undefined steps without executing tests.strict: Fails tests if undefined or pending steps exist.
When you run the Test Runner class, Cucumber:
- Loads the feature files specified in
features. - Matches steps to definitions in the
gluepackage(s). - Executes scenarios, respecting
tagsfilters. - Generates reports using the specified
pluginoptions.
Creating and Configuring a Test Runner
Let’s create a feature file, step definitions, and a Test Runner to demonstrate how it orchestrates test execution. Assume you have a Cucumber project set up with Java and Maven, as described in the Installation and Setup post.
Example: Feature File
Create a file named login.feature in src/test/resources/features:
Feature: User Login
As a user, I want to log in to the application so that I can access my account.
@smoke
Scenario: Successful login with valid credentials
Given the user is on the login page
When the user enters "user1" and "pass123"
Then the user should be redirected to the homepage
@regression
Scenario: Failed login with invalid credentials
Given the user is on the login page
When the user enters "user1" and "wrongpass"
Then the user should see an error message
Step Definitions
Create LoginSteps.java in src/test/java/steps:
package steps;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Then;
public class LoginSteps {
@Given("the user is on the login page")
public void userIsOnLoginPage() {
System.out.println("Navigating to login page");
}
@When("the user enters {string} and {string}")
public void userEntersCredentials(String username, String password) {
System.out.println("Entering username: " + username + ", password: " + password);
if (password.equals("wrongpass")) {
throw new RuntimeException("Invalid credentials");
}
}
@Then("the user should be redirected to the homepage")
public void userRedirectedToHomepage() {
System.out.println("Verifying redirection to homepage");
}
@Then("the user should see an error message")
public void userSeesErrorMessage() {
System.out.println("Verifying error message");
}
}
Create a Test Runner
Create TestRunner.java in src/test/java/runner:
package runner;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/features",
glue = "steps",
tags = "@smoke or @regression",
plugin = {
"pretty",
"html:target/cucumber-reports/cucumber.html",
"json:target/cucumber-reports/cucumber.json",
"junit:target/cucumber-reports/cucumber-junit.xml"
},
monochrome = true,
dryRun = false,
strict = false
)
public class TestRunner {
}
Explanation:
- features: Points to the directory containing feature files.
- glue: Specifies the package (
steps) containing step definitions. - tags: Runs scenarios tagged with
@smokeor@regression. - plugin: Generates console output (
pretty), HTML, JSON, and JUnit XML reports. - monochrome: Ensures clean console output.
- dryRun: Set to
falseto execute tests (iftrue, checks for undefined steps only). - strict: Set to
falseto allow undefined/pending steps (iftrue, fails on undefined steps).
Run the Tests
Run the TestRunner class in your IDE or use Maven:
mvn test
Output:
Feature: User Login
@smoke
Scenario: Successful login with valid credentials
Given the user is on the login page
When the user enters "user1" and "pass123"
Then the user should be redirected to the homepage
@regression
Scenario: Failed login with invalid credentials
Given the user is on the login page
When the user enters "user1" and "wrongpass"
java.lang.RuntimeException: Invalid credentials
...
Then the user should see an error message
2 Scenarios (1 passed, 1 failed)
6 Steps (4 passed, 1 failed, 1 skipped)
0m0.245s
Reports:
- HTML:
target/cucumber-reports/cucumber.html(viewable in a browser). - JSON:
target/cucumber-reports/cucumber.json(machine-readable). - JUnit XML:
target/cucumber-reports/cucumber-junit.xml(CI-compatible).
Advanced Test Runner Configurations
Let’s explore advanced configurations to customize test execution.
Example 1: Running Specific Tags
Update TestRunner.java to run only @smoke scenarios:
@CucumberOptions(
features = "src/test/resources/features",
glue = "steps",
tags = "@smoke",
plugin = {"pretty", "html:target/cucumber-reports/smoke.html"},
monochrome = true
)
Run the tests:
mvn test
Output:
Feature: User Login
@smoke
Scenario: Successful login with valid credentials
Given the user is on the login page
When the user enters "user1" and "pass123"
Then the user should be redirected to the homepage
1 Scenarios (1 passed)
3 Steps (3 passed)
0m0.123s
The HTML report (target/cucumber-reports/smoke.html) will only include the @smoke scenario.
Example 2: Dry Run Mode
Set dryRun = true to check for undefined steps without executing tests:
@CucumberOptions(
features = "src/test/resources/features",
glue = "steps",
tags = "@smoke or @regression",
plugin = {"pretty"},
monochrome = true,
dryRun = true
)
Run the tests:
mvn test
Output:
Shows steps without executing them, highlighting any undefined steps (none in this case since all steps are defined).
Example 3: Multiple Glue Packages
If step definitions and hooks are in different packages, specify multiple glue paths:
@CucumberOptions(
features = "src/test/resources/features",
glue = {"steps", "hooks"},
tags = "@smoke or @regression",
plugin = {"pretty", "html:target/cucumber-reports/cucumber.html"},
monochrome = true
)
This is useful for projects with separate packages for steps and hooks.
Using Test Runner with CLI
You can bypass the Test Runner and run tests directly via the Cucumber CLI, specifying options similar to @CucumberOptions:
mvn cucumber:test -Dcucumber.features=src/test/resources/features -Dcucumber.glue=steps -Dcucumber.filter.tags="@smoke or @regression" -Dcucumber.plugin=pretty,html:target/cucumber-reports/cucumber.html
However, the Test Runner is preferred for:
- Consistent configuration across team members.
- IDE integration (e.g., running tests directly in IntelliJ).
- CI/CD pipelines using Maven or Gradle.
Integrating Test Runner with CI/CD
To integrate the Test Runner with CI/CD tools like Jenkins:
- Ensure
pom.xmlincludes the Cucumber and JUnit dependencies. - Configure the Test Runner with a JUnit XML plugin:
plugin = {"junit:target/cucumber-reports/cucumber-junit.xml"} - In Jenkins, add a build step to run
mvn testand a post-build step to publish JUnit reports (target/cucumber-reports/cucumber-junit.xml). - Archive HTML reports as artifacts:
plugin = {"html:target/cucumber-reports/cucumber.html"}
This allows you to view test results and reports in Jenkins.
Best Practices for Test Runner
- Centralize Configuration: Keep all test settings in the Test Runner for consistency.
- Use Meaningful Tags: Filter tests with tags (e.g.,
@smoke,@regression) for targeted execution. - Organize Report Files: Save reports in a dedicated directory (e.g.,
target/cucumber-reports). - Enable Monochrome: Use
monochrome = truefor clean CI logs. - Test Dry Run: Periodically use
dryRun = trueto check for undefined steps. - Keep It Simple: Avoid overly complex
glueorpluginconfigurations.
Troubleshooting Test Runner Issues
- Feature Files Not Found: Verify the
featurespath is correct (e.g.,src/test/resources/features). - Step Definitions Not Found: Ensure the
gluepackage matches the step definition location (e.g.,steps). - Tag Filters Incorrect: Check tag syntax (e.g.,
@smokevs.smoke) and logical operators (and,or). - Reports Not Generated: Confirm
pluginpaths are writable and correctly formatted. - Test Runner Not Executing: Ensure
@RunWith(Cucumber.class)and@CucumberOptionsare properly annotated.
Tips for Beginners
- Start with Basic Configuration: Use minimal
features,glue, andpluginoptions initially. - Run from IDE: Test the Test Runner in your IDE (e.g., IntelliJ) for quick feedback.
- Check Console Output: Use the
prettyplugin to verify test execution. - Experiment with Tags: Try different tag filters to understand selective execution.