Building a Hybrid TestNG-Cucumber Framework (Part 7)

Samiksha KuteSamiksha Kute
12 min read

Welcome to Part 7 of our Selenium Framework Design! In this guide, we’ll learn to integrate Cucumber into our existing TestNG framework to create a hybrid TestNG-Cucumber framework. We’ll cover Gherkin syntax, feature files, step definitions, Cucumber tags, and data-driven testing, enabling our framework to support both TestNG and Cucumber tests. By the end, you’ll have a robust, business-readable automation framework ready for CI integration. Let’s get started!

Why Cucumber?

Cucumber is a Behavior-Driven Development (BDD) framework that allows test cases to be written in plain English using Gherkin syntax, making them understandable to non-technical stakeholders like business analysts (BAs). While TestNG provides features like groups, retry mechanisms, and reporting, Cucumber offers similar capabilities but with a focus on business-readable test cases. In this course, we won’t rewrite our framework from scratch using only Cucumber. Instead, we’ll build a hybrid framework, adding Cucumber on top of our existing TestNG framework to support both TestNG and Cucumber tests. This approach demonstrates how to leverage Cucumber’s high-level concepts while reusing our existing POM, BaseTest, and other components.

Scope of Part 7

  • Understand Cucumber terminology (Gherkin, feature files, scenarios, step definitions, tags, scenario outlines).

  • Integrate Cucumber into our TestNG framework.

  • Write feature files for existing tests (e.g., SubmitOrderTest, ErrorValidationTest).

  • Create step definitions to map Gherkin steps to our Selenium code.

  • Use Cucumber tags to control test execution (similar to TestNG groups).

  • Implement data-driven testing with scenario outlines.

  • Run Cucumber tests via a TestNG runner and integrate with Maven and Jenkins.

This guide assumes your project is a Maven project in Eclipse, with TestNG suites (testng.xml, Purchase.xml, ErrorValidation.xml) and the framework from Parts 1–6.

Part 1: Understanding Cucumber Terminology

What is Gherkin?

Gherkin is a business-readable, domain-specific language used to describe software behavior in a structured format. Unlike plain English test cases, which can be ambiguous (e.g., “Popup message is displayed when buttons are clicked and errors are gone” can be interpreted differently by BAs, QAs, and developers), Gherkin uses a standardized syntax to avoid misinterpretation. It defines test cases (called scenarios) using keywords like Given, When, Then, And, and But, ensuring clarity across teams.

Example of Ambiguity in Plain English:

  • Suppose a BA writes: “Popup message is displayed when buttons are clicked and errors are gone.”

    • BA’s Interpretation: Clicking a button shows a popup and clears errors.

    • QA’s Interpretation: Click a button only after ensuring no errors, then verify the popup.

  • This ambiguity can lead to misaligned development and testing, causing defects. Gherkin resolves this by enforcing a clear structure.

Key Cucumber Concepts

  1. Scenario:

    • A scenario is a test case written in Gherkin syntax.

    • Example: Testing a credit card payment with minimum due amount.

    • Structure:

        Scenario: Make minimum due amount credit card payment
          Given User is on the Pay Credit Card page
          When User fills all details
          And User selects minimum amount option
          And User clicks on Pay button
          Then Credit card confirmation page is displayed
      
    • Given: Defines preconditions (e.g., navigating to a page).

    • When: Describes user actions (e.g., filling details, clicking buttons).

    • Then: Specifies expected outcomes (e.g., confirmation page display).

    • And: Adds more actions or validations (positive statements).

    • But: Adds negative validations (e.g., “But error message is not displayed”).

  2. Feature:

    • A feature represents a high-level business requirement (e.g., “Credit card payment functionality”).

    • Multiple scenarios validate a single feature.

    • Example:

        Feature: Credit card payment
          Scenario: Make minimum due amount payment
            # Steps...
          Scenario: Pay statement balance
            # Steps...
          Scenario: Pay invalid amount (negative test)
            # Steps...
      
  3. Feature File:

    • A file with a .feature extension that contains a feature and its scenarios.

    • Acts like a TestNG test suite, grouping multiple scenarios (test cases).

    • Example: payment.feature contains all credit card payment scenarios.

  4. Step Definition:

    • A Java class that maps Gherkin steps to executable Selenium code.

    • Each Gherkin step (e.g., “Given User is on the Pay Credit Card page”) is linked to a Java method using annotations like @Given, @When, @Then

    • Example:

        @Given("User is on the Pay Credit Card page")
        public void navigateToPayCreditCardPage() {
            // Selenium code to navigate to the page
        }
      
  5. Scenario Outline:

    • Similar to a scenario but supports data-driven testing using an Examples table.

    • Replaces TestNG’s @DataProvider for parameterization.

    • Example:

        Scenario Outline: Verify word palindrome
          Given I enter word <word>
          Then The output should be <result>
          Examples:
            | word  | result |
            | refer | true   |
            | test  | false  |
      
    • The scenario runs for each row in the Examples table, substituting <word> and <result>.

  6. Background:

    • A set of steps executed before every scenario in a feature file, similar to TestNG’s @BeforeMethod.

    • Example: Navigating to the e-commerce homepage before each test.

  7. Tags:

    • Labels (e.g., @Regression, @Smoke) used to group and selectively run scenarios, similar to TestNG groups.

Why Use Cucumber?

  • Business-Readable: Non-technical stakeholders (e.g., BAs) can understand and contribute to test cases.

  • Reusability: Steps can be reused across scenarios, reducing code duplication.

  • Clarity: Gherkin’s structured syntax eliminates ambiguity.

  • Hybrid Framework: Combines Cucumber’s readability with TestNG’s robustness, allowing both plain Java TestNG tests and Cucumber tests.

Part 2: Setting Up Cucumber in the Project

Step 1: Add Cucumber Dependencies

To integrate Cucumber, add the necessary dependencies to pom.xml.

  1. Go to Maven Repository:

    • Visit mvnrepository.com.

    • Search for:

      • Cucumber Java: For core Cucumber functionality.

      • Cucumber TestNG: For running Cucumber with TestNG.

    • Copy the latest stable versions (e.g., 7.8.0).

  2. Update pom.xml:

    • Add the dependencies:

        <dependencies>
            <!-- Existing dependencies (Selenium, TestNG, etc.) -->
            <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-java</artifactId>
                <version>7.8.0</version>
            </dependency>
            <dependency>
                <groupId>io.cucumber</groupId>
                <artifactId>cucumber-testng</artifactId>
                <version>7.8.0</version>
            </dependency>
        </dependencies>
      
  3. Verify Dependencies:

    • Save pom.xml and ensure Maven downloads the dependencies (refresh the project in Eclipse).

Step 2: Install Cucumber Eclipse Plugin

To support writing feature files with proper syntax highlighting:

  1. Open Eclipse Marketplace:

    • Go to Help > Eclipse Marketplace.

    • Search for “Cucumber Eclipse Plugin” and install it.

    • Restart Eclipse after installation.

  2. Purpose:

    • The plugin provides syntax highlighting and auto-suggestions for Gherkin keywords (e.g., Feature, Scenario, Given) in .feature files.

Part 3: Creating Feature Files

We’ll convert our existing TestNG tests (SubmitOrderTest and ErrorValidationTest) into Cucumber feature files, reusing our POM classes.

Step 1: Create a Feature File for SubmitOrderTest

  1. Create a Package:

    • In src/test/java, create a new package: cucumber
  2. Create Feature File:

    • Right-click the cucumber package > New > File.

    • Name it SubmitOrder.feature with a .feature extension.

    • The Cucumber plugin provides a template with Gherkin syntax.

  3. Write the Feature File:

    • Map the SubmitOrderTest test case (login, add product to cart, checkout, submit order, verify confirmation) to Gherkin.

    • Use a Scenario Outline for data-driven testing.

    • Add a Background for the prerequisite step (launching the application).

    • Example:

        Feature: Purchase the order from Ecommerce website
          Background:
            Given I landed on Ecommerce page
          Scenario Outline: Positive test of submitting the order
            Given I logged in with username <name> and password <password>
            When I add product <productName> to cart
            And checkout <productName> and submit the order
            Then "THANK YOU FOR THE ORDER." message is displayed on Confirmation page
            Examples:
              | name                     | password      | productName  |
              | samikshak@gmail.com      | Sam@12345     | ZARA COAT 3  |
      
    • Explanation:

      • Feature: Describes the business requirement (purchasing an order).

      • Background: Runs before each scenario, launching the e-commerce page (similar to launchApplication in BaseTest).

      • Scenario Outline: Defines the test with placeholders (<name>, <password>, <productName>) for data-driven testing.

      • Examples: Provides test data, similar to TestNG’s @DataProvider.

      • Steps:

        • Given: Logs in with username and password from the Examples table.

        • When/And: Adds a product to the cart and submits the order.

        • Then: Verifies the confirmation message (static text in quotes).

Step 2: Create Step Definitions

  1. Create a Step Definitions Package:

    • In src/test/java, create a package: stepDefinitions
  2. Create a Step Definition Class:

    • Right-click the stepDefinitions package > New > Class.

    • Name it StepImplementation.java

  3. Implement Steps:

    • Map each Gherkin step to a Java method using Cucumber annotations (@Given, @When, @Then).

    • Reuse existing POM classes and BaseTest methods.

    • Example:

        package stepdefinitions;
      
        import java.io.IOException;
      
        import org.testng.Assert;
      
        import io.cucumber.java.en.And;
        import io.cucumber.java.en.Given;
        import io.cucumber.java.en.Then;
        import io.cucumber.java.en.When;
        import pageobjects.CartPage;
        import pageobjects.CheckoutPage;
        import pageobjects.ConfirmationPage;
        import pageobjects.LandingPage;
        import pageobjects.ProductCatalogue;
        import testComponents.BaseTest;
      
        public class StepImplementation extends BaseTest {
            public LandingPage landingPage;
            public ProductCatalogue productCatalogue;
            public ConfirmationPage confirmationPage;
      
            @Given("I Landed on Ecommerce page")
            public void i_landed_on_Ecommerce_page() throws IOException {
                landingPage = launchApplication();
            }
      
            @Given("^Logged in with username (.+) and password (.+)$")
            public void logged_in_with_username_and_password(String email, String password) {
                productCatalogue = landingPage.loginApplication(email, password);
            }
      
            @When("^I add (.+) to Cart$")
            public void i_add_product_to_cart(String productName) throws InterruptedException {
                productCatalogue.getProducList();
                productCatalogue.addProductToCart(productName);
            }
      
            @And("^Checkout (.+) and submit the order$")
            public void checkout_and_submit_the_order(String productName) throws InterruptedException {
                CartPage cartPage = productCatalogue.goToCartPage();
                boolean match = cartPage.verifyProductIsDisplayed(productName);
                Assert.assertTrue(match);
                CheckoutPage checkoutPage = cartPage.goToCheckOutPage();
                checkoutPage.selectCountry("india");
                confirmationPage = checkoutPage.submitOrder();
            }
      
            @Then("{string} message is displayed on ConfirmationPage")
            public void message_is_displayed_on_ConfirmationPage(String string) {
                String confirmMessage = confirmationPage.verifyConfirmationMessage();
                Assert.assertTrue(confirmMessage.equalsIgnoreCase(string));
                driver.close();
            }
      
            @Then("{string} message is displayed")
            public void something_message_is_displayed(String string) {
                Assert.assertEquals(string, landingPage.getErrorMessage());
                driver.close();
            }
        }
      
    • Explanation:

      • Inheritance: Extends BaseTest to reuse launchApplication and WebDriver setup.

      • Global Variables: LandingPage, ProductCatalogue, and ConfirmationPage are declared globally to maintain state across steps.

      • Annotations:

        • @Given("I Landed on Ecommerce page"): Sets up the initial state by launching the application.

        • @Given("^Logged in with username (.+) and password (.+)$"): Uses regular expressions with (.+) to capture any username/password values from test data.

        • @When("^I add (.+) to Cart$"): Captures any product name and adds it to the shopping cart.

        • @And("^Checkout (.+) and submit the order$"): Handles the checkout process for any specified product.

        • @Then steps: Verify expected results like confirmation messages or error messages.

      • Dynamic Parameters: Uses (.+) and {string} patterns to capture different values (like usernames, passwords, product names) from the test scenarios, making tests reusable with different data.

      • Assertions: Use TestNG’s Assert to verify outcomes.

      • Driver Cleanup: driver.close() ensures the browser closes after each test.

Step 3: Create a Test Runner

To run the feature file, create a TestNG runner class.

  1. Create Runner Class:

    • In src/test/java/cucumber, create a class: TestNGTestRunner.java
  2. Configure Cucumber Options:

    • Example:

        package cucumber;
      
        import io.cucumber.testng.AbstractTestNGCucumberTests;
        import io.cucumber.testng.CucumberOptions;
      
        @CucumberOptions(
            features = "src/test/java/cucumber",
            glue = "stepDefinitions",
            monochrome = true,
            plugin = {"html:target/cucumber.html"}
        )
        public class TestNGTestRunner extends AbstractTestNGCucumberTests {
        }
      
    • Explanation:

      • @CucumberOptions:

        • features: Path to the feature files (src/test/java/cucumber).

        • glue: Path to the step definitions package (stepDefinitions).

        • monochrome = true: Ensures readable console output.

        • plugin: Generates an HTML report at target/cucumber.html.

      • extends AbstractTestNGCucumberTests: Enables Cucumber to run with TestNG, supporting TestNG assertions in step definitions.

  3. Run the Test:

    • Right-click TestNGTestRunner.java > Run As > TestNG Test.

    • Cucumber scans the cucumber package, runs SubmitOrder.feature, maps steps to StepImplementation.java, and executes the test.

    • Output:

      • The test logs in, adds “ZARA COAT 3” to the cart, checks out, submits the order, and verifies the confirmation message.

      • An HTML report is generated at target/cucumber.html

Step 4: Create Feature File for ErrorValidationTest

  1. Create Feature File:

    • In src/test/java/cucumber, create ErrorValidations.feature.

    • Example:

        Feature: "Error Validation"
            This is feature description
            @ErrorValidation:
            Scenario Outline: Positive Test of Submitting the Order
                Given I Landed on Ecommerce page
                When Logged in with username <name> and password <password>
                Then "Incorrect email or password." message is displayed
      
                Examples:
                    | name                  | password  |
                    | wrong_email@gmail.com | Sam@12345 |
      
    • Explanation:

      • Feature: Validates error handling (e.g., incorrect login credentials).

      • Scenario Outline: Tests login with incorrect credentials.

      • No Background: Reuses the “I landed on Ecommerce page” step directly.

      • Examples: Provides invalid credentials to trigger the error message.

  2. Add Step Definition:

    • In StepImplementation.java, add the new step (reuse existing steps for landing and login):

        @Then("{string} message is displayed")
        public void error_message_displayed(String message) {
            Assert.assertEquals(landingPage.getErrorMessage(), message);
            driver.close();
        }
      
    • Explanation:

      • Maps to “Then Incorrect email or password. message is displayed”.

      • Uses {string} to capture the error message.

      • Verifies the error message on the LandingPage and closes the browser.

  3. Run the Test:

    • Running TestNGTestRunner executes both SubmitOrder.feature and ErrorValidations.feature (all feature files in the cucumber package).

    • Result: The error validation test fails (as expected) due to incorrect credentials, and the report shows the outcome.

Part 4: Using Cucumber Tags

Tags control which scenarios to run, similar to TestNG groups.

  1. Add Tags:

    • Update the feature files:

        @Regression
        Feature: Purchase the order from Ecommerce website
          # ... (SubmitOrder.feature content)
      
        @ErrorValidation
        Feature: Error validation on Ecommerce website
          # ... (ErrorValidations.feature content)
      
  2. Update Test Runner:

    • Modify TestNGTestRunner.java to run only specific tags:

        @CucumberOptions(
            features = "src/test/java/cucumber",
            glue = "stepDefinitions",
            monochrome = true,
            tags = "@Regression",
            plugin = {"html:target/cucumber.html"}
        )
        public class TestNGTestRunner extends AbstractTestNGCucumberTests {
        }
      
    • Explanation:

      • tags = "@Regression": Runs only scenarios/features with the @Regression tag (i.e., SubmitOrder.feature).

      • In newer Cucumber versions, use tags = "@Regression" (not {@Regression}).

  3. Run the Test:

    • Right-click TestNGTestRunner.java > Run As > TestNG Test.

    • Result: Only SubmitOrder.feature runs, skipping ErrorValidations.feature.

Part 5: Integrating with Maven and Jenkins

To run Cucumber tests via Maven and Jenkins, add a new profile to pom.xml.

  1. Update pom.xml:

    • Add a CucumberTests profile:

        <profiles>
            <!-- Existing profiles (Regression, Purchase, ErrorValidation) -->
            <profile>
                <id>CucumberTests</id>
                <build>
                    <pluginManagement>
                        <plugins>
                            <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-surefire-plugin</artifactId>
                                <version>3.0.0-M5</version>
                                <configuration>
                                    <includes>
                                        <include>**/TestNGTestRunner.java</include>
                                    </includes>
                                </configuration>
                            </plugin>
                        </plugins>
                    </pluginManagement>
                </build>
            </profile>
        </profiles>
      
    • Explanation:

      • <includes>: Specifies the TestNGTestRunner.java file to run (unlike TestNG XML files in previous profiles).

      • **/ searches all folders for TestNGTestRunner.java.

  2. Run via Maven:

    • Open a terminal, navigate to the project root, and run:

        mvn test -PCucumberTests
      
    • Result: Executes TestNGTestRunner, running feature files based on the tags filter (e.g., @Regression).

  3. Update Jenkins Job:

    • Open the existing Jenkins job (from Part 6).

    • Go to Configure > Build > Invoke top-level Maven targets.

    • Add the new profile:

        test -PCucumberTests
      
    • Alternatively, parameterize the profile (as in Part 6):

      • Add a Choice Parameter named profile with options: Regression, Purchase, ErrorValidation, CucumberTests.

      • Update the Maven command to test -P"$profile".

    • Save and run the job with profile=CucumberTests.

    • Result: Jenkins runs the Cucumber tests, generating the cucumber.html report in the target folder.

Part 6: Key Differences Between TestNG and Cucumber

  • TestNG Features Not Supported in Cucumber:

    • @DataProvider: Use Scenario Outline with Examples instead.

    • TestNG groups: Use Cucumber tags.

    • TestNG XML suites: Use feature files and the TestNG runner.

  • Why Use TestNG Runner?:

    • Cucumber requires a runner (TestNG or JUnit) to execute feature files.

    • Since our framework uses TestNG assertions, we extend AbstractTestNGCucumberTests for compatibility.

  • Reusability:

    • Cucumber steps (e.g., “I landed on Ecommerce page”) are reusable across feature files, reducing code duplication.

    • The same POM classes (e.g., LandingPage, ProductCatalogue) are reused, maintaining framework consistency.

Key Takeaways

  1. Cucumber Basics:

    • Gherkin: A structured language for business-readable test cases.

    • Feature Files: Contain scenarios (test cases) and act as test suites.

    • Step Definitions: Map Gherkin steps to Selenium code.

    • Scenario Outline: Enables data-driven testing with Examples.

  2. Hybrid Framework:

    • Added Cucumber to the existing TestNG framework, reusing POM and BaseTest.

    • Created feature files for SubmitOrderTest and ErrorValidationTest.

    • Used a TestNG runner (AbstractTestNGCucumberTests) to execute Cucumber tests.

  3. Tags:

    • Used @Regression and @ErrorValidation to selectively run tests, similar to TestNG groups.
  4. Maven and Jenkins:

    • Added a CucumberTests profile to run TestNGTestRunner via Maven.

    • Integrated with Jenkins for CI execution.

  5. Reporting:

    • Generated basic Cucumber HTML reports (target/cucumber.html).

Check out the complete code repository below:

Happy automating!

0
Subscribe to my newsletter

Read articles from Samiksha Kute directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Samiksha Kute
Samiksha Kute

Passionate Learner!