What is Cucumber with Maven?
Cucumber with Maven involves using Maven, a widely-used build automation tool, to manage Cucumber test projects. Maven simplifies dependency management, test execution, and reporting for Cucumber tests by defining project structure, libraries, and build configurations in a pom.xml
file. This integration streamlines development, testing, and CI/CD workflows.
Why Use Cucumber with Maven?
- Dependency Management: Automatically download and manage libraries (e.g., Cucumber, Selenium).
- Standardized Structure: Enforce a consistent project layout for scalability.
- Build Automation: Run tests, generate reports, and package projects with simple commands.
- CI/CD Integration: Seamlessly integrate with tools like Jenkins or GitLab CI.
- Customization: Configure test execution with profiles, properties, and plugins.
Setting Up a Cucumber-Maven Project
Let’s create a Maven-based Cucumber project with Selenium to automate a login test on saucedemo.com. We’ll configure Maven to manage dependencies, run tests, and generate reports.
Prerequisites
- Install Tools:
- Java JDK (11 or later).
- Maven: Download from maven.apache.org and set
MAVEN_HOME
. - IDE: IntelliJ IDEA or Eclipse (optional but recommended).
- ChromeDriver: Compatible with your Chrome browser, placed in a project directory (e.g.,
drivers/
).
- Verify Maven:
mvn -version
Step 1: Create a Maven Project
Create a new Maven project using the command line or your IDE.
Command Line
mvn archetype:generate -DgroupId=com.example -DartifactId=cucumber-maven-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
IDE (IntelliJ)
- File > New > Project > Maven.
- Set GroupId:
com.example
, ArtifactId:cucumber-maven-demo
. - Finish and open the project.
Step 2: Configure pom.xml
Replace the default pom.xml
with the following to include Cucumber, Selenium, and Maven plugins:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>cucumber-maven-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<cucumber.version>7.18.0</cucumber.version>
<selenium.version>4.25.0</selenium.version>
<junit.version>4.13.2</junit.version>
</properties>
<dependencies>
<!-- Cucumber Dependencies -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<!-- Selenium Dependency -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
<scope>test</scope>
</dependency>
<!-- JUnit Dependency -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Maven Surefire Plugin for Test Execution -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<includes>
<include>**/TestRunner.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Explanation:
- Properties: Centralizes version numbers for easy updates.
- Dependencies: Includes Cucumber, Selenium, and JUnit for testing.
- Plugins:
maven-compiler-plugin
: Ensures Java 11 compatibility.maven-surefire-plugin
: Runs tests via theTestRunner
class.
Step 3: Create Project Structure
Set up the following structure:
cucumber-maven-demo/
├── src/
│ ├── test/
│ │ ├── java/
│ │ │ ├── steps/ # Step definitions and hooks
│ │ │ └── runner/ # TestRunner class
│ │ └── resources/
│ │ └── features/ # Feature files
├── drivers/ # ChromeDriver
├── reports/ # Test reports
├── pom.xml
Step 4: Create a Feature File
Create 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 "standard_user" and "secret_sauce"
And the user clicks the login button
Then the user should be redirected to the dashboard
Step 5: Create Step Definitions
Create LoginSteps.java
in src/test/java/steps
:
package steps;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.*;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class LoginSteps {
private WebDriver driver;
@Before
public void setUp() {
System.setProperty("webdriver.chrome.driver", "drivers/chromedriver");
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@After
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
@Given("the user is on the login page")
public void userIsOnLoginPage() {
driver.get("https://www.saucedemo.com/");
}
@When("the user enters {string} and {string}")
public void userEntersCredentials(String username, String password) {
driver.findElement(By.id("user-name")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
}
@And("the user clicks the login button")
public void userClicksLoginButton() {
driver.findElement(By.id("login-button")).click();
}
@Then("the user should be redirected to the dashboard")
public void userRedirectedToDashboard() {
String currentUrl = driver.getCurrentUrl();
Assert.assertTrue("User not redirected to dashboard", currentUrl.contains("inventory.html"));
}
}
Step 6: 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",
plugin = {
"pretty",
"html:reports/cucumber.html",
"json:reports/cucumber.json",
"junit:reports/cucumber-junit.xml"
},
monochrome = true
)
public class TestRunner {
}
Explanation:
- features: Points to feature files.
- glue: Specifies step definitions package.
- tags: Runs only
@smoke
tests. - plugin: Generates HTML, JSON, and JUnit XML reports.
- monochrome: Ensures clean console output.
Step 7: Run Tests with Maven
Ensure ChromeDriver is in drivers/
. Run tests from the project root:
mvn clean test
Output:
[INFO] --- maven-surefire-plugin:3.5.0:test (default-test) @ cucumber-maven-demo ---
...
1 Scenario (1 passed)
4 Steps (4 passed)
0m5.123s
...
[INFO] BUILD SUCCESS
Reports:
- HTML:
reports/cucumber.html
(view in browser). - JSON:
reports/cucumber.json
(machine-readable). - JUnit XML:
reports/cucumber-junit.xml
(CI-compatible).
Enhancing Cucumber-Maven Integration
Let’s explore advanced Maven configurations to optimize test execution.
Example 1: Running Specific Tags
Pass tags via Maven to run specific test suites.
Update pom.xml
:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<includes>
<include>**/TestRunner.java</include>
</includes>
<systemPropertyVariables>
<cucumber.filter.tags>${cucumber.tags}</cucumber.filter.tags>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
Run smoke tests:
mvn clean test -Dcucumber.tags="@smoke"
Why?
- Allows dynamic tag selection without modifying
TestRunner
.
Example 2: Maven Profiles for Environments
Use Maven profiles to switch between environments (e.g., dev, prod).
Update pom.xml
:
<profiles>
<profile>
<id>dev</id>
<properties>
<base.url>https://dev.saucedemo.com</base.url>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<base.url>https://www.saucedemo.com</base.url>
</properties>
</profile>
</profiles>
Update LoginSteps.java
:
@Given("the user is on the login page")
public void userIsOnLoginPage() {
String baseUrl = System.getProperty("base.url", "https://www.saucedemo.com/");
driver.get(baseUrl);
}
Run tests for dev:
mvn clean test -Pdev
Run tests for prod:
mvn clean test -Pprod
Why?
- Supports testing across multiple environments.
- Reduces hardcoding.
Example 3: Parallel Test Execution
Run tests in parallel to reduce execution time using the maven-surefire-plugin
.
Update pom.xml
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<includes>
<include>**/TestRunner.java</include>
</includes>
<parallel>methods</parallel>
<threadCount>4</threadCount>
</configuration>
</plugin>
Note: Ensure step definitions are thread-safe (e.g., use Dependency Injection to avoid shared WebDriver instances, as shown in the Dependency Injection post).
Run tests:
mvn clean test
Why?
- Speeds up large test suites.
- Requires careful management of shared resources.
Example 4: Adding Third-Party Reports
Integrate ExtentReports for advanced reporting. Add dependency to pom.xml
:
<dependency>
<groupId>tech.grasshopper</groupId>
<artifactId>extentreports-cucumber7-adapter</artifactId>
<version>1.14.0</version>
<scope>test</scope>
</dependency>
Update TestRunner.java
:
@CucumberOptions(
features = "src/test/resources/features",
glue = "steps",
tags = "@smoke",
plugin = {
"pretty",
"html:reports/cucumber.html",
"json:reports/cucumber.json",
"junit:reports/cucumber-junit.xml",
"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"
},
monochrome = true
)
Create extent.properties
in src/test/resources
:
extent.reporter.spark.start=true
extent.reporter.spark.out=reports/ExtentReport.html
screenshot.dir=reports/screenshots/
screenshot.rel.path=screenshots/
Run tests:
mvn clean test
Output:
- Generates an ExtentReport at
reports/ExtentReport.html
.
Why?
- Provides interactive, detailed reports for team reviews.
Best Practices for Cucumber with Maven
- Centralize Versions: Use
<properties>
inpom.xml
to manage dependency versions. - Organize Structure: Follow Maven’s standard directory layout (
src/test/java
,src/test/resources
). - Use Profiles: Configure environments or test types with Maven profiles.
- Generate Reports: Include HTML, JSON, and JUnit plugins for comprehensive reporting.
- Validate Locally: Run
mvn clean test
locally before CI/CD integration. - Keep Tests Independent: Use DI or hooks to ensure scenario isolation.
Troubleshooting Cucumber-Maven Issues
- Dependency Errors: Run
mvn clean install
to download dependencies. - Test Not Found: Ensure
TestRunner.java
is in the correct package and included insurefire-plugin
. - Report Not Generated: Verify
plugin
paths inTestRunner
(e.g.,reports/cucumber.html
). - Selenium Errors: Confirm ChromeDriver path and version compatibility.
- Tag Issues: Check
-Dcucumber.tags
syntax (e.g.,@smoke
, notsmoke
).
Tips for Beginners
- Start Simple: Begin with minimal
pom.xml
dependencies. - Use Maven Commands: Practice
mvn clean
,mvn test
, andmvn install
. - Check Reports: Open HTML reports to verify test results.
- Explore Plugins: Experiment with
surefire-plugin
and reporting plugins.