top of page
hand-businesswoman-touching-hand-artificial-intelligence-meaning-technology-connection-go-

Step by Step Implementation Cucumber BDD Framework using Java, Selenium, Jenkins, GIT, Extent Report

-By Gayathri Vimalan


Let’s try to understand first what is BDD? How it helps to build better software:

Do you know when BBD was born?. Earlier TDD( Test Driven Development) was helping to qualify the quality code. It is very simple to describe, but it’s proven hard to teach and hard to learn. That's where BBD comes into Dan North’s mind. So he replaced with “behavior” instead of “test” in which the tests were written in plain English language using a simple Given/When/Then syntax. BDD mainly focuses on the behavior of the system rather than technical specifications. So it gave the organization much confidence that it satisfies end user expectations.



BDD is all about collaboration between Business teams and Technical teams. It generates the common documentation which can be understood by all teams and stakeholders. BDD streamlines the requirements of the process and also brings the value to QA. Because every line of the production code, configuration or even specification is directly linked to its own particular scenario, which leads to the ultimate project business goal. This will end up knowing how much business value each line of our code must deliver to the end user. So Cucumber is one of the software tools that supports BDD. Let’s build a sample project with Cucumber.


Before creating the project in Eclipse. Make sure you have installed Java and Maven and set the environment variables as shown in the following screenshot.




Please make sure you have downloaded the MAVEN plugin from Eclipse. If not please refer below:


Open Eclipse and go to help>Eclipse Marketplace>search maven>Eclipse m2e and install. Please refer to the screenshot below.



Step 1: Setting up on Eclipse


Create a Maven project


Go to File > New > Other



Select Maven> Maven Project and click Next


Then select default Workspace location and click Next


Select Catalog and Group Id and click Next


Now we have to give a name for our project. Here I have given the same name for Group Id and Artifact Id. Then click Finish.


Go to Eclipse Help>Eclipse Marketplace> search cucumber. Install Cucumber Plugins. Refer below for snapshots.

  1. Cucumber Eclipse Plugin

  2. Natural 0.9



Once the project is created in Eclipse, the structure will look like below. By default the highlighted package will be created, so please go ahead and delete those packages.


Now we need to add dependency in our pom.xml. Here are the list dependencies needed for our project. By default you will have JUnit dependency.

  • Cucumber JVM: Java

  • Cucumber JVM: JUnit

  • Selenium Java

  • WebDriverManager

  • Apache Commons IO

  • ExtentReports Cucumber7 Adapter

  • ExtentReports

  • Allure Cucumber 7 JVM


Once you added dependencies in your pom.xml please save it and right click on the project > select Maven>Update Project.


Once the project is updated, the Maven repository will look as shown below,


In order to make sure the project is configured with all the required Jars and Plugins, please go to the project and right click and select Run as>Maven install and click.


After clicking Maven install you should be able to see the Console output as Build success


Now we have completed setting up the project. Next, we can configure the project into a cucumber project. Right click on the project and go to Configure and select Convert to Cucumber Project as shown below


Step 2: Create Feature file and write feature.


We need to create feature files in the src/test/resources folder. For that we need to create a source folder under the project and name it as src/test/resources and click finish. Please refer screenshot below,



Under src/test/resources, create a folder and name it as features. Under features folder create a file and name it as login.feature in order to test the user login functionality.

Features are defined in .feature files. Refer below snapshot


Most commonly used keywords in Gherkin : Feature, Scenario, Given, When, Then, And, But, Background, Scenario Outline, Examples etc.


This article uses Facebook login feature for testing. Based on Gherkin guidelines, let’s write a sample feature in login.feature.


Feature: Login

Background: The User opens login Page
 Given User Launches Chrome Browser
 When user opens facebook  portal link "https://www.facebook.com/"
 Then User should see the  page title "Facebook - log in or sign up"

Scenario Outline: Validating the Login functionality
    When User enters Username as "<username>" and Password as "<password>" 
    Then User clicks on Login button with expected status as "<status>"
    Then User should see the Facebook Home page on successful login status "<status>"
    
 Examples:
    | username | password   | status      |
    |          |            | Both Fail   |
    | Valid    |            | Missing Password  |    
    | Valid    | Valid      | Pass        |

Step 3: Create Page Objects


Here we have to implement page objects in separate classes for the UI page. We can call them wherever required in steps definitions. In future, if there are any changes in locators, we can just refer to the particular Page Object Model (POM) class and update at once.

By using this approach we can also reduce the code redundancy. Under src/test/java, create a package called ‘pageObjects’ and create a class called loginPage.java. Please refer snapshot below.



In LoginPage.java, define WebElements as variables using Annotation @findBy. And also create methods for actions performed on WebElements.


package pageObjects;


 
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.CacheLookup;
 import org.openqa.selenium.support.FindBy;
 import org.openqa.selenium.support.PageFactory;

 import stepDefinitions.BaseClass;

 public class LoginPage extends BaseClass {
  
  public LoginPage (WebDriver webDriver)
  {
   PageFactory.initElements(webDriver, this);
  }
  
  @FindBy(xpath="//input[@id='email']")
  @CacheLookup
  WebElement inputUsername;
  
  
  
  @FindBy(xpath ="//input[@id='pass']")
  @CacheLookup
  WebElement inputPassword;
  
  
  
  @FindBy(xpath="//button[@name='login']")
  @CacheLookup
  WebElement btnLogin; 
  
  
  
  @FindBy(xpath="//div/a[1][@aria-label='Facebook']")
  @CacheLookup
  WebElement divHomePageTitle;
  
  @FindBy(xpath="//div[contains(text(),'The email')]")
  @CacheLookup
  WebElement divErrorMsgUN;
  
  @FindBy(xpath="//div[contains(text(),'The password')]")
  @CacheLookup
  WebElement divErrorMsgPWD;
  
    
  public void SetUserName(String uName) {
   inputUsername.clear();
   inputUsername.sendKeys(uName);
  }
  
   
  public void SetPassword(String pwd) {
   inputPassword.clear();
   inputPassword.sendKeys(pwd);
  }  
  
  public void ClickBtnLogin() {
   btnLogin.click();
  }
  
    
  public String getHomePgTitle() {
    return divHomePageTitle.getAttribute("aria-label");  
  }
  
  public String getErrMsgUN() {
    return divErrorMsgUN.getText();  
  }
  
  public String getErrMsgPWD() {
    return divErrorMsgPWD.getText();  
  }
  
  
}

Step 4:Writing Step Definitions


Now under src/test/java, we need to create a package and name it as stepDefinitions. And under stepDefinitions create a class and name it as loginSteps. We also need to create BaseClass and Hooks under stepDefinitions.

Here we used BaseClass so that we can avoid code duplication.

We used Hooks to allow us to perform actions at various points in the cucumber test cycle. This is typically used for setup and teardown before and after each scenario.

Please refer to the snapshot for better understanding.



Now how are we going to execute our scenario? After we added our feature files, we had to define and link steps. So here step definition comes into the picture. Step definition is the glue between the feature file written in Gherkin language. When Cucumber executes a Step in a Scenario, it will look for a matching Step Definition to execute. The yellow text shows in login.feature signifies steps within the defined feature that are not yet implemented.

The easiest way to auto generate the step definitions stubs is to just run your feature file to get step definition suggestions in the console. Refer snapshot below,


Now our step definitions suggestion file will be populated in the console for the test cases in our feature file that do not have step definitions for a particular scenario.

Copy the entire suggested step definitions and paste it in loginSteps. Then, remove the below highlighted yellow code in your loginSteps.


Now go to stepDefinitions package >loginSteps.java class and implement all the test steps as shown below:


package stepDefinitions;

import org.junit.Assert;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import pageObjects.LoginPage;
import utilities.Helper;

public class LoginSteps extends BaseClass {
 
 @Given("User Launches Chrome Browser")
 public void user_launches_chrome_browser() {
  loginPage = new LoginPage(Helper.getDriver());   
 }

 @When("user opens facebook  portal link {string}")
 public void user_opens_facebook_portal_link(String url) {
    Helper.openPage(url);    
 }
 
 @Then("User should see the  page title {string}")
 public void user_should_see_the_page_title(String string) {
   String loginPgTitle = Helper.getTitle();
   Assert.assertEquals(string, loginPgTitle); 
 }
 
 @When("User enters Username as {string} and Password as {string}")
 public void user_enters_username_as_and_password_as(String userName, String password) {
    if(userName.equalsIgnoreCase("Valid") && password.equalsIgnoreCase("Valid"))
    {
    userName= Helper.GetUserName();
    password= Helper.GetPassword();
    }
  loginPage.SetUserName(userName);
  loginPage.SetPassword(password);  
  
  System.out.println("User Name: "+ userName);
  System.out.println("Password: "+ password);
 }

 @Then("User clicks on Login button with expected status as {string}")
 public void user_clicks_on_login_button(String expectedStatus) {
  loginPage.ClickBtnLogin();
  
  if (expectedStatus == "Both Fail")
  {
   String userNameValMessage = loginPage.getErrMsgUN();
   String pwdValMessage= loginPage.getErrMsgUN();
   
   Assert.assertEquals("Please enter your user name", userNameValMessage);
   Assert.assertEquals("Please enter your password", pwdValMessage);
   return;
  }
  else if (expectedStatus == "Missing Password")
  {
   String commonMsg =loginPage.getErrMsgPWD();
   Assert.assertEquals("Invalid username and password Please try again",commonMsg);
   return;
  }
 }
 
 @Then("User should see the Facebook Home page on successful login status {string}")
 public void user_should_see_the_facebook_home_page_on_successful_login_status(String status) throws InterruptedException { 
  
 
  if (status.equalsIgnoreCase("Pass"))
  {
   Assert.assertEquals(loginPage.getHomePgTitle(), "Facebook");
   System.out.println("Login Passed");
   Assert.assertEquals(Helper.getTitle(), "facebook");
  } 
 }
}

Step 5: Writing Hooks/Base class


In the below example, we implemented Hooks for initial configurations of the project. Cucumber’s Before hook is mainly responsible for initializing the driver and opening a web browser which is a prerequisite for all scenarios. Cucumber’s After hook is responsible for capturing a snapshot of failure and close the browser. I have added the code to take the screenshot of the failed scenario in @After Hook.


package stepDefinitions;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import utilities.Helper;

public class Hooks {
 @Before
    public static void setUp() {
     
     Helper.setUpDriver();
    }
 
    @After
    public static void tearDown(Scenario scenario) {
 
        if(scenario.isFailed()) {
            final byte[] screenshot = ((TakesScreenshot) Helper.getDriver()).getScreenshotAs(OutputType.BYTES);
            scenario.attach(screenshot, "image/png", scenario.getName()); 
        }   
         
        Helper.tearDown();
    }

}

We need to create Base class to maintain the page object classes. In our project we have only one page object class right now. In future if we have more page object classes we can manage them here and also any reusable methods that are applicable to all classes. Using Base class we can avoid code duplication.



package stepDefinitions;

import pageObjects.LoginPage;

public class BaseClass {
 public LoginPage loginPage;

}

Step 6 : Create Helper Class


Helper class is responsible for initializing the web driver, web driver wait, defining the timeouts, creating a private constructor of the class to declare the web driver, so whenever we create an object of this class, a new web browser is invoked. This Helper Class contains methods that help in assisting our project.


Go to src/test/java> create package called Utilities. Under Utilities create a Class called Helper.java as shown below.


package utilities;

import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import