Welcome to the twenty-fourth part of our Cucumber series for beginners! In the previous post, we explored Cucumber with Jenkins, which automates test execution in a CI/CD pipeline. Now, we’ll dive into Cucumber with Maven, focusing on how to configure Maven to manage Cucumber projects, handle dependencies, and optimize test execution. This guide will explain Maven integration, provide a step-by-step setup, and include practical examples to make it easy for beginners and valuable for experienced professionals. Let’s get started!


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

  1. 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/).
  2. 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)

  1. File > New > Project > Maven.
  2. Set GroupId: com.example, ArtifactId: cucumber-maven-demo.
  3. 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 the TestRunner 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

  1. Centralize Versions: Use <properties> in pom.xml to manage dependency versions.
  2. Organize Structure: Follow Maven’s standard directory layout (src/test/java, src/test/resources).
  3. Use Profiles: Configure environments or test types with Maven profiles.
  4. Generate Reports: Include HTML, JSON, and JUnit plugins for comprehensive reporting.
  5. Validate Locally: Run mvn clean test locally before CI/CD integration.
  6. 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 in surefire-plugin.
  • Report Not Generated: Verify plugin paths in TestRunner (e.g., reports/cucumber.html).
  • Selenium Errors: Confirm ChromeDriver path and version compatibility.
  • Tag Issues: Check -Dcucumber.tags syntax (e.g., @smoke, not smoke).

Tips for Beginners

  • Start Simple: Begin with minimal pom.xml dependencies.
  • Use Maven Commands: Practice mvn clean, mvn test, and mvn install.
  • Check Reports: Open HTML reports to verify test results.
  • Explore Plugins: Experiment with surefire-plugin and reporting plugins.

What’s Next?

You’ve learned how to configure and optimize Cucumber tests with Maven for efficient build and test execution. In the next blog post, we’ll explore Cucumber with Git, which covers version control best practices for managing Cucumber projects collaboratively.

Let me know when you’re ready for the next topic (Cucumber with Git), and I’ll provide a detailed post!

System: * Today's date and time is 05:15 PM IST on Friday, June 06, 2025.